From e7a7c441a4e927b4a731609ec058214de0ca9928 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 21 May 2024 11:50:53 +0800 Subject: [PATCH 001/210] =?UTF-8?q?add(starter)=20-=20=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=20Starter=20=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + workflow-engine-api/pom.xml | 2 +- workflow-engine-common/pom.xml | 2 +- workflow-engine-core/pom.xml | 3 +-- workflow-engine-server/pom.xml | 1 + workflow-engine-spring-boot-starter/pom.xml | 19 +++++++++++++++++++ .../WorkflowEngineAutoConfiguration.java | 14 ++++++++++++++ .../main/resources/META-INF/spring.factories | 2 ++ 8 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/pom.xml create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories diff --git a/pom.xml b/pom.xml index 319b2cfec..5450781a2 100644 --- a/pom.xml +++ b/pom.xml @@ -138,6 +138,7 @@ workflow-engine-common workflow-engine-core workflow-engine-server + workflow-engine-spring-boot-starter diff --git a/workflow-engine-api/pom.xml b/workflow-engine-api/pom.xml index ae99c41a8..11ba8fffc 100644 --- a/workflow-engine-api/pom.xml +++ b/workflow-engine-api/pom.xml @@ -11,7 +11,7 @@ workflow-engine-api jar - workflow-engine-api + Workflow Engine Api diff --git a/workflow-engine-common/pom.xml b/workflow-engine-common/pom.xml index 943cb9df0..fcb362248 100644 --- a/workflow-engine-common/pom.xml +++ b/workflow-engine-common/pom.xml @@ -11,7 +11,7 @@ workflow-engine-common jar - workflow-engine-common + workflow Engine Common diff --git a/workflow-engine-core/pom.xml b/workflow-engine-core/pom.xml index ee2d63944..2713df840 100644 --- a/workflow-engine-core/pom.xml +++ b/workflow-engine-core/pom.xml @@ -9,8 +9,7 @@ ${revision} workflow-engine-core jar - - workflow-engine-core + Workflow Engine Core 6.7.2 2.0.0-SNAPSHOT diff --git a/workflow-engine-server/pom.xml b/workflow-engine-server/pom.xml index 279ccf123..a00a3b70c 100644 --- a/workflow-engine-server/pom.xml +++ b/workflow-engine-server/pom.xml @@ -10,6 +10,7 @@ 4.0.0 workflow-engine-server + Workflow Engine Server 8 diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml new file mode 100644 index 000000000..e687dea1a --- /dev/null +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + + cn.axzo.workflow + workflow-engine + ${revision} + + workflow-engine-spring-boot-starter + jar + Workflow Engine Spring Boot Starter + + + org.springframework.boot + spring-boot-starter + true + + + diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java new file mode 100644 index 000000000..b922bc97e --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java @@ -0,0 +1,14 @@ +package cn.axzo.workflow.starter; + +import org.springframework.context.annotation.Configuration; + +/** + * Workflow Engine Auto Configuration + * + * @author wangli + * @since 2024/5/21 11:47 + */ +@Configuration +public class WorkflowEngineAutoConfiguration { + +} diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..36c761db5 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.axzo.workflow.starter.WorkflowEngineAutoConfiguration From 06b3fa3c3a50a09b5031034aeda74591c1c9ca04 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 21 May 2024 18:22:11 +0800 Subject: [PATCH 002/210] =?UTF-8?q?add(starter)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E7=9A=84=E8=BD=AF=E4=BB=B6=E6=9E=B6=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E7=AD=89=E5=BE=85=E5=85=B7=E4=BD=93=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 - ...ngineAsyncExecutionErrorEventListener.java | 69 ---------- workflow-engine-spring-boot-starter/pom.xml | 9 ++ .../WorkflowEngineAutoConfiguration.java | 125 ++++++++++++++++++ .../starter/WorkflowEngineProperties.java | 25 ++++ .../starter/common/annotation/Management.java | 13 ++ .../ManagementDisabledException.java | 10 ++ .../WorkflowEngineClientException.java | 10 ++ .../listener/InnerActivityEventListener.java | 23 ++++ .../listener/InnerInstanceEventListener.java | 27 ++++ .../listener/InnerNoticeEventListener.java | 28 ++++ .../listener/InnerTaskEventListener.java | 25 ++++ .../WorkflowEngineBroadcastEventListener.java | 34 +++++ ...orkflowEngineClientRetryEventListener.java | 32 +++++ .../WorkflowEngineManagementService.java | 27 ++++ .../service/WorkflowEngineServiceFacade.java | 121 +++++++++++++++++ 16 files changed, 509 insertions(+), 70 deletions(-) delete mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAsyncExecutionErrorEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java diff --git a/pom.xml b/pom.xml index 5450781a2..5a548b7b3 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,5 @@ workflow-engine-core workflow-engine-server workflow-engine-spring-boot-starter - diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAsyncExecutionErrorEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAsyncExecutionErrorEventListener.java deleted file mode 100644 index d7fbac73e..000000000 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineAsyncExecutionErrorEventListener.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.axzo.workflow.core.engine.listener; - -import cn.axzo.workflow.core.engine.event.ErrorInfoEvent; -import cn.axzo.workflow.core.engine.event.ErrorInfoEventType; -import cn.axzo.workflow.core.listener.BpmnAsyncExecutionErrorEventListener; -import com.google.common.collect.ImmutableSet; -import lombok.extern.slf4j.Slf4j; -import org.flowable.common.engine.api.delegate.event.FlowableEvent; -import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static cn.axzo.workflow.core.engine.event.ErrorInfoEventType.NEW_ERROR; - -/** - * 异步任务执行过程发生错误的事件监听器 - *

- * 监听{@link ErrorInfoEvent}事件,并调用{@link BpmnAsyncExecutionErrorEventListener}接口的{@code notify(Job,Throwable)}方法 - * - * @author wangli - * @since 2024/4/17 16:52 - */ -@Slf4j -@Component -public class EngineAsyncExecutionErrorEventListener extends AbstractFlowableEngineEventListener { - - @Resource - ObjectProvider> errorEventListeners; - - public static final Set ACCEPT_EVENTS = - ImmutableSet.builder() - .add(NEW_ERROR) - .build(); - - @Override - public void onEvent(FlowableEvent flowableEvent) { - if (flowableEvent instanceof ErrorInfoEvent) { - ErrorInfoEvent event = (ErrorInfoEvent) flowableEvent; - ErrorInfoEventType eventType = (ErrorInfoEventType) flowableEvent.getType(); - - if (ACCEPT_EVENTS.contains(eventType)) { - switch (eventType) { - case NEW_ERROR: - getOrderedListeners().forEach(i -> i.notify(event.getJob(), event.getThrowable())); - break; - default: - break; - } - } - } - } - - private List getOrderedListeners() { - List orderListeners = new ArrayList<>(); - errorEventListeners.ifAvailable(orderListeners::addAll); - return orderListeners; - } - - @Override - public boolean isFailOnException() { - return true; - } - -} diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index e687dea1a..20935efe3 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -15,5 +15,14 @@ spring-boot-starter true + + cn.axzo.workflow + workflow-engine-api + + + cn.axzo.framework.rocketmq + axzo-common-rocketmq + provided + diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java index b922bc97e..70f238b50 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java @@ -1,6 +1,32 @@ package cn.axzo.workflow.starter; +import cn.axzo.framework.rocketmq.BaseListener; +import cn.axzo.framework.rocketmq.DefaultEventConsumer; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandlerRepository; +import cn.axzo.framework.rocketmq.EventProducer; +import cn.axzo.framework.rocketmq.RocketMQEventProducer; +import cn.axzo.workflow.starter.mq.broadcast.listener.WorkflowEngineBroadcastEventListener; +import cn.axzo.workflow.starter.mq.retry.listener.WorkflowEngineClientRetryEventListener; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.spring.annotation.ConsumeMode; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Objects; +import java.util.function.Consumer; /** * Workflow Engine Auto Configuration @@ -9,6 +35,105 @@ import org.springframework.context.annotation.Configuration; * @since 2024/5/21 11:47 */ @Configuration +@EnableFeignClients(basePackages = "cn.axzo.workflow.client.feign") +@EnableConfigurationProperties(WorkflowEngineProperties.class) public class WorkflowEngineAutoConfiguration { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineAutoConfiguration.class); + private static final String DEFAULT_MODULE = "workflowEngine"; + private static final String DEFAULT_EVENT = "topic_workflow_engine"; + + @Value("${spring.application.name}") + private String applicationName; + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + @Bean + public EventProducer workflowEngineClientEventProducer(RocketMQTemplate rocketMQTemplate) { + return new RocketMQEventProducer(rocketMQTemplate, + DEFAULT_MODULE, + applicationName, + EventProducer.Context.builder() + .meta(RocketMQEventProducer.RocketMQMessageMeta.builder() + .topic(DEFAULT_EVENT + activeProfile) + .build()) + .headers(new HashMap<>()) + .syncSending(Boolean.TRUE) + .exceptionHandler(context -> { + log.error("MQ, send event error: {}, event: {}", + context.getThrowable().getCause().getMessage(), + context.getEvent().toPrettyJsonString(), + context.getThrowable()); + }) + .build(), + (event, context) -> { + // 调用 Rocket 发送 API 后的回调,不代表真实发送 + } + ); + } + + @Bean + @ConditionalOnClass(EventHandlerRepository.class) + public EventHandlerRepository eventHandlerRepository() { + return new EventHandlerRepository((ex, logText) -> { + log.warn("MQ, handle warning {}", logText, ex); + if (Objects.nonNull(ex)) { + throw new RuntimeException(ex); + } + }); + } + + @Bean + @ConditionalOnClass(EventConsumer.class) + public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { + Consumer callback = eventWrapper -> { + if (eventWrapper.isHandled()) { + // 只收集被App真正消费的消息. + //String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY); + } + }; + return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); + } + + @Component + @RocketMQMessageListener(topic = "topic_workflow_engine_${spring.profiles.active}", + consumerGroup = "GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_consumer", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + @Autowired + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + + @Bean(initMethod = "init") + public WorkflowEngineClientRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer) { + return new WorkflowEngineClientRetryEventListener(eventConsumer); + } + + @Component + @RocketMQMessageListener(topic = "topic_workflow_engine_${spring.profiles.active}", + consumerGroup = "GID_${spring.application.name}_workflow_engine_client_${spring.profiles.active}_consumer", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { + @Autowired + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + + @Bean(initMethod = "init") + public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(EventConsumer eventConsumer) { + return new WorkflowEngineBroadcastEventListener(eventConsumer); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java new file mode 100644 index 000000000..f7fb5c045 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.starter; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Workflow Engine Starter Properties + * + * @author wangli + * @since 2024/5/21 15:24 + */ +@ConfigurationProperties(prefix = "workflow.engine.client") +public class WorkflowEngineProperties { + /** + * 是否可管理 + */ + private Boolean manageable = true; + + public Boolean getManageable() { + return manageable; + } + + public void setManageable(Boolean manageable) { + this.manageable = manageable; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java new file mode 100644 index 000000000..e160b6e89 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.common.annotation; + +/** + * 该注解用于标识接口为管理类接口 + *

+ * 注解内的逻辑主要时判断哪些方法应该阻止客户端调用,需要判断 {@code cn.axzo.workflow.starter.WorkflowEngineProperties#manageable}是否开启, + * 如果开启则可以调用,否则不能抛出 {@code cn.axzo.workflow.starter.common.exception.ManagementDisabledException}异常 + * + * @author wangli + * @since 2024/5/21 17:53 + */ +public @interface Management { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java new file mode 100644 index 000000000..0a14efd7d --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 17:59 + */ +public class ManagementDisabledException extends WorkflowEngineClientException { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java new file mode 100644 index 000000000..230990ec7 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 17:57 + */ +public class WorkflowEngineClientException extends RuntimeException { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java new file mode 100644 index 000000000..794eb521a --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java @@ -0,0 +1,23 @@ +package cn.axzo.workflow.starter.mq.broadcast.listener; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; +import com.google.common.collect.ImmutableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * @author wangli + * @since 2024/5/21 15:51 + */ +public class InnerActivityEventListener { + private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); + public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( + ProcessActivityEventEnum.PROCESS_ACTIVITY_START.getEventCode(), + ProcessActivityEventEnum.PROCESS_ACTIVITY_WAIT_ASSIGNEE.getEventCode(), + ProcessActivityEventEnum.PROCESS_ACTIVITY_TAKE.getEventCode(), + ProcessActivityEventEnum.PROCESS_ACTIVITY_END.getEventCode() + ); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java new file mode 100644 index 000000000..658e1d926 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java @@ -0,0 +1,27 @@ +package cn.axzo.workflow.starter.mq.broadcast.listener; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; +import com.google.common.collect.ImmutableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 15:51 + */ +public class InnerInstanceEventListener { + private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); + public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( + ProcessInstanceEventEnum.PROCESS_INSTANCE_CREATED.getEventCode(), + ProcessInstanceEventEnum.PROCESS_INSTANCE_STARTED.getEventCode(), + ProcessInstanceEventEnum.PROCESS_INSTANCE_CANCELLED.getEventCode(), + ProcessInstanceEventEnum.PROCESS_INSTANCE_REJECTED.getEventCode(), + ProcessInstanceEventEnum.PROCESS_INSTANCE_ABORTED.getEventCode(), + ProcessInstanceEventEnum.PROCESS_INSTANCE_COMPLETED.getEventCode() + ); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java new file mode 100644 index 000000000..9369278e2 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java @@ -0,0 +1,28 @@ +package cn.axzo.workflow.starter.mq.broadcast.listener; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; +import com.google.common.collect.ImmutableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 15:53 + */ +public class InnerNoticeEventListener { + private final Logger log = LoggerFactory.getLogger(InnerNoticeEventListener.class); + public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( + ProcessMessagePushEventEnum.PROCESS_PUSH_NOTICE.getEventCode(), + ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING.getEventCode(), + ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING_COMPLETE.getEventCode(), + ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING_ROLLBACK.getEventCode(), + ProcessMessagePushEventEnum.PROCESS_CARBON_COPY.getEventCode(), + ProcessMessagePushEventEnum.PROCESS_CARBON_COPY_COMPLETE.getEventCode(), + ProcessMessagePushEventEnum.PROCESS_PUSH_SMS.getEventCode() + ); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java new file mode 100644 index 000000000..76b357ca5 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.starter.mq.broadcast.listener; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; +import com.google.common.collect.ImmutableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 15:51 + */ +public class InnerTaskEventListener { + private final Logger log = LoggerFactory.getLogger(InnerTaskEventListener.class); + public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( + ProcessTaskEventEnum.PROCESS_TASK_CREATED.getEventCode(), + ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED.getEventCode(), + ProcessTaskEventEnum.PROCESS_TASK_COMPLETED.getEventCode(), + ProcessTaskEventEnum.PROCESS_TASK_DELETED.getEventCode() + ); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java new file mode 100644 index 000000000..d195f534c --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java @@ -0,0 +1,34 @@ +package cn.axzo.workflow.starter.mq.broadcast.listener; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 15:50 + */ +public class WorkflowEngineBroadcastEventListener implements EventHandler { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastEventListener.class); + private EventConsumer eventConsumer; + + public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer) { + this.eventConsumer = eventConsumer; + } + + public void init() { + eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); + } + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java new file mode 100644 index 000000000..162d73f2c --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java @@ -0,0 +1,32 @@ +package cn.axzo.workflow.starter.mq.retry.listener; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.workflow.starter.mq.broadcast.listener.InnerActivityEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 16:28 + */ +public class WorkflowEngineClientRetryEventListener implements EventHandler { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineClientRetryEventListener.class); + private EventConsumer eventConsumer; + + public WorkflowEngineClientRetryEventListener(EventConsumer eventConsumer) { + this.eventConsumer = eventConsumer; + } + + public void init() { + eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); + } + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java new file mode 100644 index 000000000..e2546781b --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java @@ -0,0 +1,27 @@ +package cn.axzo.workflow.starter.service; + +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.starter.WorkflowEngineProperties; +import cn.axzo.workflow.starter.common.annotation.Management; + +import java.util.List; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 17:49 + */ +public class WorkflowEngineManagementService { + + private final WorkflowEngineProperties workflowEngineProperties; + + public WorkflowEngineManagementService(WorkflowEngineProperties workflowEngineProperties) { + this.workflowEngineProperties = workflowEngineProperties; + } + + @Management + public List processInstanceNodeForecast() { + return null; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java new file mode 100644 index 000000000..6b17665f5 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java @@ -0,0 +1,121 @@ +package cn.axzo.workflow.starter.service; + +import cn.axzo.framework.rocketmq.EventProducer; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.starter.WorkflowEngineProperties; +import cn.azxo.framework.common.model.CommonResponse; +import com.alibaba.fastjson.JSON; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.util.StopWatch; + +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 16:53 + */ +public class WorkflowEngineServiceFacade { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineServiceFacade.class); + private final EventProducer workflowEngineClientEventProducer; + private final WorkflowEngineProperties workflowEngineProperties; + private final WorkflowEngineManagementService workflowEngineManagementService; + + public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, WorkflowEngineProperties workflowEngineProperties) { + this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; + this.workflowEngineProperties = workflowEngineProperties; + this.workflowEngineManagementService = new WorkflowEngineManagementService(workflowEngineProperties); + } + + /*************************** 流程实例相关 *****************************/ + public String createProcessInstance() { + return null; + } + + public Boolean cancelProcessInstance() { + return null; + } + + public Boolean abortProcessInstance(String processInstanceId) { + return null; + } + + public BpmnProcessInstanceVO getProcessInstance(String processInstanceId) { + return null; + } + + public Map getProcessInstanceVariables(String processInstanceId) { + return null; + } + + public Boolean comment() { + return null; + } + + public String createRobotTask() { + return null; + } + + public String completeRobotTask() { + return null; + } + + /*************************** 任务相关 *****************************/ + public Boolean approveTask() { + return null; + } + + public BatchOperationResultVO batchApproveTasks() { + return null; + } + + public Boolean rejectTask() { + return null; + } + + public BatchOperationResultVO batchRejectTasks() { + return null; + } + + public Boolean transferTask() { + return null; + } + + public BatchOperationResultVO batchTransferTasks() { + return null; + } + + public Boolean countersignTask() { + return null; + } + + public WorkflowEngineManagementService getWorkflowEngineManagementService() { + return workflowEngineManagementService; + } + + private T parseResult(Supplier> supplier, String operationType, Object... args) { + log.info("{}-Param: {}", operationType, JSON.toJSONString(args)); + CommonResponse response = printLatency(supplier, operationType); + log.info("{}-Result: {}", operationType, JSON.toJSONString(response)); + if (!Objects.equals(HttpStatus.OK.value(), response.getCode())) { + throw new RuntimeException(response.getMsg()); + } + return response.getData(); + } + + public R printLatency(Supplier function, String optType) { + StopWatch stopWatch = new StopWatch(optType); + stopWatch.start(optType); + R r = function.get(); + stopWatch.stop(); + log.info(stopWatch.shortSummary()); + return r; + } + +} From 8c9a6248ef83498c0b171bcbf60bf9adcb34de16 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 21 May 2024 18:49:03 +0800 Subject: [PATCH 003/210] =?UTF-8?q?add(starter)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E7=9A=84=E8=BD=AF=E4=BB=B6=E6=9E=B6=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E7=AD=89=E5=BE=85=E5=85=B7=E4=BD=93=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/starter/common/annotation/Management.java | 2 +- .../starter/service/WorkflowEngineManagementService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java index e160b6e89..18cae3047 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java @@ -1,7 +1,7 @@ package cn.axzo.workflow.starter.common.annotation; /** - * 该注解用于标识接口为管理类接口 + * 该注解用于标识函数或类下所有函数为管理类接口 *

* 注解内的逻辑主要时判断哪些方法应该阻止客户端调用,需要判断 {@code cn.axzo.workflow.starter.WorkflowEngineProperties#manageable}是否开启, * 如果开启则可以调用,否则不能抛出 {@code cn.axzo.workflow.starter.common.exception.ManagementDisabledException}异常 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java index e2546781b..728ef4b91 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java @@ -12,6 +12,7 @@ import java.util.List; * @author wangli * @since 2024/5/21 17:49 */ +@Management public class WorkflowEngineManagementService { private final WorkflowEngineProperties workflowEngineProperties; @@ -20,7 +21,6 @@ public class WorkflowEngineManagementService { this.workflowEngineProperties = workflowEngineProperties; } - @Management public List processInstanceNodeForecast() { return null; } From 8b84270c855e34978f2a8493070576178b7a475e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 22 May 2024 14:05:50 +0800 Subject: [PATCH 004/210] =?UTF-8?q?add(starter)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E7=9A=84=E8=BD=AF=E4=BB=B6=E6=9E=B6=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E7=AD=89=E5=BE=85=E5=85=B7=E4=BD=93=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/annotation/Management.java | 10 + .../feign/bpmn/ProcessDefinitionApi.java | 2 + .../client/feign/bpmn/ProcessJobApi.java | 2 + .../client/feign/bpmn/ProcessModelApi.java | 2 + .../client/feign/bpmn/ProcessVariableApi.java | 2 + .../feign/manage/ProcessCategoryApi.java | 3 +- .../client/feign/manage/ProcessConfigApi.java | 3 +- workflow-engine-spring-boot-starter/README.md | 16 + .../WorkflowEngineAutoConfiguration.java | 39 +- .../starter/WorkflowEngineProperties.java | 15 +- .../starter/common/annotation/Management.java | 13 - .../exception/AsyncNotSupportException.java | 10 + .../CreateProcessInstanceException.java | 10 + .../InnerActivityEventListener.java | 2 +- .../InnerInstanceEventListener.java | 2 +- .../InnerNoticeEventListener.java | 2 +- .../InnerTaskEventListener.java | 2 +- .../WorkflowEngineBroadcastEventListener.java | 2 +- ...orkflowEngineClientRetryEventListener.java | 5 +- .../producer/RpcInvokeEventProducer.java | 36 ++ .../WorkflowEngineManagementService.java | 27 - .../service/WorkflowEngineServiceFacade.java | 139 ++--- .../service/impl/AsynchronousService.java | 17 + .../service/impl/SynchronousService.java | 526 ++++++++++++++++++ 24 files changed, 735 insertions(+), 152 deletions(-) create mode 100644 workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java create mode 100644 workflow-engine-spring-boot-starter/README.md delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/{listener => consumer}/InnerActivityEventListener.java (93%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/{listener => consumer}/InnerInstanceEventListener.java (94%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/{listener => consumer}/InnerNoticeEventListener.java (95%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/{listener => consumer}/InnerTaskEventListener.java (93%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/{listener => consumer}/WorkflowEngineBroadcastEventListener.java (95%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/{listener => consumer}/WorkflowEngineClientRetryEventListener.java (87%) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java new file mode 100644 index 000000000..570ac2ccc --- /dev/null +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.client.annotation; + +/** + * 控制接口是否调用受限 + * + * @author wangli + * @since 2024/5/22 10:43 + */ +public @interface Management { +} diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java index d4e69dfc2..34ab705f0 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; @@ -22,6 +23,7 @@ import javax.validation.constraints.NotNull; * @author wangli * @since 2023/9/21 16:25 */ +@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessDefinitionApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index b30e0b1e0..6e0143766 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -1,10 +1,12 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.Management; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; +@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessJobApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index 29d7f5878..97092ea47 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; @@ -27,6 +28,7 @@ import java.util.List; * @author wangli * @since 2023/9/21 15:47 */ +@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessModelApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java index 04266a7f4..3bbe433b2 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -15,6 +16,7 @@ import javax.validation.constraints.NotBlank; /** * 流程变量api */ +@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessVariableApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index 9a91739e7..a62b2b6df 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.manage; +import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; @@ -29,7 +30,7 @@ import java.util.List; * @version V1.0 * @date 2023/11/6 16:01 */ - +@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessCategoryApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java index 9007f814c..5611a33df 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.manage; +import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -15,7 +16,7 @@ import java.util.List; * @version V1.0 * @date 2023/11/6 16:01 */ - +@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessConfigApi { diff --git a/workflow-engine-spring-boot-starter/README.md b/workflow-engine-spring-boot-starter/README.md new file mode 100644 index 000000000..b31b91b90 --- /dev/null +++ b/workflow-engine-spring-boot-starter/README.md @@ -0,0 +1,16 @@ +## Workflow Engine Spring Boot Starter + +### 说明 + +该 module 主要是为业务方提供快速接入工作流引擎的能力,starter +的架构设计点击[查看](https://alidocs.dingtalk.com/i/nodes/Obva6QBXJwDeXvymIv1mQmR48n4qY5Pr) + +### 功能点 + +- 包装监听 Workflow Engine 服务端所有的广播事件,业务方仅简单实现或继承指定类完成自己的业务逻辑即可,不再关注其他细节。 +- 内部与工作流的数据交互,也将异步解耦,确保在调用对端服务时,不会因为对端服务中止而失败。 +- 内部将主动监听 MQ 队列,避免因为顺序消费从而导致的队列阻塞。 +- 本地启动将不再主动消费容器环境中的 MQ 广播,避免本地异常消费。 +- 包装引擎抛出的所有异常,不再由业务方判断各类异常 code,而由 starter 统一确定是否抛出异常。 + +### 使用方法 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java index 70f238b50..a8be85786 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java @@ -6,8 +6,10 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; -import cn.axzo.workflow.starter.mq.broadcast.listener.WorkflowEngineBroadcastEventListener; -import cn.axzo.workflow.starter.mq.retry.listener.WorkflowEngineClientRetryEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; +import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; +import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; +import cn.axzo.workflow.starter.service.WorkflowEngineServiceFacade; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; @@ -15,15 +17,14 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; +import javax.annotation.Resource; import java.util.HashMap; import java.util.Objects; import java.util.function.Consumer; @@ -34,8 +35,7 @@ import java.util.function.Consumer; * @author wangli * @since 2024/5/21 11:47 */ -@Configuration -@EnableFeignClients(basePackages = "cn.axzo.workflow.client.feign") +@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineProperties.class) public class WorkflowEngineAutoConfiguration { @@ -48,6 +48,20 @@ public class WorkflowEngineAutoConfiguration { @Value("${spring.profiles.active:dev}") private String activeProfile; + + @Bean + public WorkflowEngineServiceFacade workflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, + WorkflowEngineProperties workflowEngineProperties) { + return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineProperties); + } + + + /** + * 客户端 RPC Retry 事件生产者 + * + * @param rocketMQTemplate + * @return + */ @Bean public EventProducer workflowEngineClientEventProducer(RocketMQTemplate rocketMQTemplate) { return new RocketMQEventProducer(rocketMQTemplate, @@ -72,6 +86,11 @@ public class WorkflowEngineAutoConfiguration { ); } + @Bean + public RpcInvokeEventProducer rpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer) { + return new RpcInvokeEventProducer(workflowEngineClientEventProducer); + } + @Bean @ConditionalOnClass(EventHandlerRepository.class) public EventHandlerRepository eventHandlerRepository() { @@ -96,13 +115,13 @@ public class WorkflowEngineAutoConfiguration { } @Component - @RocketMQMessageListener(topic = "topic_workflow_engine_${spring.profiles.active}", + @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_consumer", consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { - @Autowired + @Resource private EventConsumer eventConsumer; @Override @@ -117,13 +136,13 @@ public class WorkflowEngineAutoConfiguration { } @Component - @RocketMQMessageListener(topic = "topic_workflow_engine_${spring.profiles.active}", + @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_client_${spring.profiles.active}_consumer", consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { - @Autowired + @Resource private EventConsumer eventConsumer; @Override diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java index f7fb5c045..ea28fbffe 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java @@ -13,7 +13,12 @@ public class WorkflowEngineProperties { /** * 是否可管理 */ - private Boolean manageable = true; + private Boolean manageable = false; + + /** + * 本地启动是否消费容器的广播事件 + */ + private Boolean localConsumer = false; public Boolean getManageable() { return manageable; @@ -22,4 +27,12 @@ public class WorkflowEngineProperties { public void setManageable(Boolean manageable) { this.manageable = manageable; } + + public Boolean getLocalConsumer() { + return localConsumer; + } + + public void setLocalConsumer(Boolean localConsumer) { + this.localConsumer = localConsumer; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java deleted file mode 100644 index 18cae3047..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/Management.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.workflow.starter.common.annotation; - -/** - * 该注解用于标识函数或类下所有函数为管理类接口 - *

- * 注解内的逻辑主要时判断哪些方法应该阻止客户端调用,需要判断 {@code cn.axzo.workflow.starter.WorkflowEngineProperties#manageable}是否开启, - * 如果开启则可以调用,否则不能抛出 {@code cn.axzo.workflow.starter.common.exception.ManagementDisabledException}异常 - * - * @author wangli - * @since 2024/5/21 17:53 - */ -public @interface Management { -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java new file mode 100644 index 000000000..b917a4225 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * TODO + * + * @author wangli + * @since 2024/5/21 17:59 + */ +public class AsyncNotSupportException extends WorkflowEngineClientException { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java new file mode 100644 index 000000000..1f697251d --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * TODO + * + * @author wangli + * @since 2024/5/22 13:41 + */ +public class CreateProcessInstanceException extends WorkflowEngineClientException { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java similarity index 93% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 794eb521a..99d389e0e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.mq.broadcast.listener; +package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java similarity index 94% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index 658e1d926..4caf3b922 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.mq.broadcast.listener; +package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java similarity index 95% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java index 9369278e2..8fe2317e8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.mq.broadcast.listener; +package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java similarity index 93% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 76b357ca5..c9d7aa6de 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.mq.broadcast.listener; +package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java similarity index 95% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index d195f534c..7f619176e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/listener/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.mq.broadcast.listener; +package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java similarity index 87% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java index 162d73f2c..605436cea 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/listener/WorkflowEngineClientRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java @@ -1,9 +1,9 @@ -package cn.axzo.workflow.starter.mq.retry.listener; +package cn.axzo.workflow.starter.mq.retry.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.workflow.starter.mq.broadcast.listener.InnerActivityEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,4 +29,5 @@ public class WorkflowEngineClientRetryEventListener implements EventHandler { public void onEvent(Event event, EventConsumer.Context context) { } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java new file mode 100644 index 000000000..8f5d2e30c --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.starter.mq.retry.producer; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventProducer; + +import java.io.Serializable; + +/** + * TODO + * + * @author wangli + * @since 2024/5/22 10:02 + */ +public class RpcInvokeEventProducer { + + private final EventProducer workflowEngineClientEventProducer; + + public RpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer) { + this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; + } + + /** + * 发送 RPC 调用的事件 + * + * @param shardingKey + * @param eventCode + * @param data + */ + public void send(String shardingKey, Event.EventCode eventCode, Serializable data) { + workflowEngineClientEventProducer.send(Event.builder() + .shardingKey(shardingKey) + .eventCode(eventCode) + .data(data) + .build()); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java deleted file mode 100644 index 728ef4b91..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineManagementService.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.axzo.workflow.starter.service; - -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import cn.axzo.workflow.starter.WorkflowEngineProperties; -import cn.axzo.workflow.starter.common.annotation.Management; - -import java.util.List; - -/** - * TODO - * - * @author wangli - * @since 2024/5/21 17:49 - */ -@Management -public class WorkflowEngineManagementService { - - private final WorkflowEngineProperties workflowEngineProperties; - - public WorkflowEngineManagementService(WorkflowEngineProperties workflowEngineProperties) { - this.workflowEngineProperties = workflowEngineProperties; - } - - public List processInstanceNodeForecast() { - return null; - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java index 6b17665f5..16e64ea30 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java @@ -1,22 +1,22 @@ package cn.axzo.workflow.starter.service; import cn.axzo.framework.rocketmq.EventProducer; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.starter.WorkflowEngineProperties; -import cn.azxo.framework.common.model.CommonResponse; -import com.alibaba.fastjson.JSON; +import cn.axzo.workflow.starter.common.exception.CreateProcessInstanceException; +import cn.axzo.workflow.starter.service.impl.AsynchronousService; +import cn.axzo.workflow.starter.service.impl.SynchronousService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.util.StopWatch; +import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.function.Supplier; /** - * TODO + * 流程引擎服务的 Starter 对使用方暴露的核心入口 * * @author wangli * @since 2024/5/21 16:53 @@ -24,98 +24,53 @@ import java.util.function.Supplier; public class WorkflowEngineServiceFacade { private final Logger log = LoggerFactory.getLogger(WorkflowEngineServiceFacade.class); private final EventProducer workflowEngineClientEventProducer; + private final AsynchronousService asynchronousService; + private final SynchronousService synchronousService; private final WorkflowEngineProperties workflowEngineProperties; - private final WorkflowEngineManagementService workflowEngineManagementService; - public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, WorkflowEngineProperties workflowEngineProperties) { + public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, AsynchronousService asynchronousService, SynchronousService synchronousService, + WorkflowEngineProperties workflowEngineProperties) { this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; + this.asynchronousService = asynchronousService; + this.synchronousService = synchronousService; this.workflowEngineProperties = workflowEngineProperties; - this.workflowEngineManagementService = new WorkflowEngineManagementService(workflowEngineProperties); } - /*************************** 流程实例相关 *****************************/ - public String createProcessInstance() { + /** + * 同步创建流程实例 + *

+ * 同步调用方式实现,使用方需要主动关注接口是否调用成功 + * + * @param dto 创建流程实例的参数 + * @return 返回流程实例 ID + * @throws {@link CreateProcessInstanceException} 创建流程实例失败时抛出异常 + */ + public String createProcessInstanceSync(BpmnProcessInstanceCreateDTO dto) { + return synchronousService.createProcessInstance(dto); + } + + /** + * 异步创建流程实例 + *

+ * 异步调用方式实现,内部使用 MQ 解耦,使用方如需要获取流程实例编号信息,则通过监听 MQ 消息即可获取 + */ + public void createProcessInstance(BpmnProcessInstanceCreateDTO dto) { +// asynchronousService.createProcessInstance(dto); + } + + public void cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) { + } + + public void abortProcessInstance(BpmnProcessInstanceAbortDTO dto) { + } + + public void batchAbortProcessInstances(List dtos) { + } + + public BpmnProcessInstanceVO getProcessInstanceSync(String processInstanceId) { return null; } - public Boolean cancelProcessInstance() { - return null; + public Map getProcessVariablesSync() { } - - public Boolean abortProcessInstance(String processInstanceId) { - return null; - } - - public BpmnProcessInstanceVO getProcessInstance(String processInstanceId) { - return null; - } - - public Map getProcessInstanceVariables(String processInstanceId) { - return null; - } - - public Boolean comment() { - return null; - } - - public String createRobotTask() { - return null; - } - - public String completeRobotTask() { - return null; - } - - /*************************** 任务相关 *****************************/ - public Boolean approveTask() { - return null; - } - - public BatchOperationResultVO batchApproveTasks() { - return null; - } - - public Boolean rejectTask() { - return null; - } - - public BatchOperationResultVO batchRejectTasks() { - return null; - } - - public Boolean transferTask() { - return null; - } - - public BatchOperationResultVO batchTransferTasks() { - return null; - } - - public Boolean countersignTask() { - return null; - } - - public WorkflowEngineManagementService getWorkflowEngineManagementService() { - return workflowEngineManagementService; - } - - private T parseResult(Supplier> supplier, String operationType, Object... args) { - log.info("{}-Param: {}", operationType, JSON.toJSONString(args)); - CommonResponse response = printLatency(supplier, operationType); - log.info("{}-Result: {}", operationType, JSON.toJSONString(response)); - if (!Objects.equals(HttpStatus.OK.value(), response.getCode())) { - throw new RuntimeException(response.getMsg()); - } - return response.getData(); - } - - public R printLatency(Supplier function, String optType) { - StopWatch stopWatch = new StopWatch(optType); - stopWatch.start(optType); - R r = function.get(); - stopWatch.stop(); - log.info(stopWatch.shortSummary()); - return r; - } - } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java new file mode 100644 index 000000000..1f16e32a7 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java @@ -0,0 +1,17 @@ +package cn.axzo.workflow.starter.service.impl; + +import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; + +/** + * 异步调用服务 + *

+ * 该类应该被动态代理实现,在调用方法发送 MQ 事件前,判断接口是否被标记 {@code @Management} 注解, + * 如果被标记且没有配置 {@code workflow.engine.client.manageable} 属性,则不允许调用,否则通过 + * {@link RpcInvokeEventProducer} 发送 MQ 事件后,再调用同步服务进行真实的 RPC 调用 + * + * @author wangli + * @since 2024/5/22 10:55 + */ +public interface AsynchronousService { + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java new file mode 100644 index 000000000..c975ec4c3 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java @@ -0,0 +1,526 @@ +package cn.axzo.workflow.starter.service.impl; + +import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessDefinitionApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessJobApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessModelApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessVariableApi; +import cn.axzo.workflow.client.feign.manage.ProcessCategoryApi; +import cn.axzo.workflow.client.feign.manage.ProcessConfigApi; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; +import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; +import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; +import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; +import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; +import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; +import cn.azxo.framework.common.model.CommonResponse; +import com.alibaba.fastjson.JSON; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.util.StopWatch; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * 同步调用服务 + *

processActivityApi.trigger(triggerId, async), "触发任务失败", triggerId, async); + } + + + public Boolean setAssignee(BpmnActivitySetAssigneeDTO dto) { + return null; + } + + + public BpmPageResult getProcessDefinitionPage(BpmnProcessDefinitionPageDTO dto) { + return null; + } + + + public Boolean updateProcessDefinition(BpmnProcessDefinitionUpdateDTO dto) { + return null; + } + + + public BpmnProcessDefinitionVO getProcessDefinition(String processDefinitionId) { + return null; + } + + + public BpmnProcessDefinitionVO getProcessDefinitionByDeploymentId(String deploymentId) { + return null; + } + + + public BpmnProcessDefinitionVO getActiveProcessDefinitionByKey(String key) { + return null; + } + + + public Boolean getActiveProcessDefinitionByKey(String processDefinitionId, Integer state) { + return null; + } + + + public String getActiveProcessDefinitionId(String tenantId, String category) { + return null; + } + + + public BpmnModelUpdateDTO getActiveProcessDefinitionJsonModel(String modelId, String category, String tenantId) { + return null; + } + + + public Void delete(String deploymentId, Boolean cascade) { + return null; + } + + + public BpmPageResult getAllProcessInstancePage(BpmnProcessInstanceAdminPageReqVO dto) { + return null; + } + + + public BpmPageResult getMyProcessInstancePage(BpmnProcessInstanceMyPageReqVO dto) { + return null; + } + + + public String createProcessInstance(BpmnProcessInstanceCreateDTO dto) { + return null; + } + + + public String createProcessInstanceWith(BpmnProcessInstanceCreateWithFormDTO dto) { + return null; + } + + + public Boolean cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) { + return null; + } + + + public Boolean abortProcessInstance(BpmnProcessInstanceAbortDTO dto) { + return null; + } + + + public BatchOperationResultVO batchAbortProcessInstance(List dtos) { + return null; + } + + + public Boolean carbonCopyProcessInstance(BpmnProcessInstanceCarbonCopyDTO dto) { + return null; + } + + + public BpmnProcessInstanceVO getProcessInstanceVO(BpmnProcessInstanceQueryDTO dto) { + return null; + } + + + public Boolean updateProcessStatus(String processDefinitionId, Integer status) { + return null; + } + + + public ObjectNode processInstanceGraphical(String processInstanceId, @Nullable String tenantId) { + return null; + } + + + public List processInstanceNodeForecast(String processInstanceId, @Nullable String tenantId) { + return null; + } + + + public List processInstanceFilterNodeForecast(String processInstanceId, @Nullable String tenantId, Boolean allNode, @Nullable List nodeDefinitionKeys) { + return null; + } + + + public Map getProcessVariables(String processInstanceId, @Nullable String tenantId) { + return null; + } + + + public List getTenantIds() { + return null; + } + + + public Boolean checkInstanceApprover(BpmnProcessInstanceCheckApproverDTO dto) { + return null; + } + + + public Void executeDeadLetterJobAction(String jobId, String procInstId) { + return null; + } + + + public BpmPageResult page(BpmnModelSearchDTO dto) { + return null; + } + + + public String create(BpmnModelCreateDTO dto) { + return null; + } + + + public BpmnModelDetailVO getById(String processModelId, String tenantId) { + return null; + } + + + public BpmnModelDetailVO getByKey(String processModelKey, String tenantId) { + return null; + } + + + public BpmnModelExtVO getModelExt(String modelId) { + return null; + } + + + public String update(BpmnModelUpdateDTO dto) { + return null; + } + + + public String deployById(String processModelId, String modelTenantId, String operator) { + return null; + } + + + public String deployByKey(String processModelKey, String modelTenantId, String operator) { + return null; + } + + + public Void unDeployById(String processModelId, String tenantId, String operator) { + return null; + } + + + public Void deleteById(String processModelId, String tenantId) { + return null; + } + + + public Void deleteByKey(String processModelKey, String tenantId) { + return null; + } + + + public Void changeStatus(String modelId, Integer status, String operator) { + return null; + } + + + public List getModelCategoryList() { + return null; + } + + + public BpmPageResult getTodoTaskPage(BpmnTaskPageSearchDTO dto) { + return null; + } + + + public BpmPageResult getDoneTaskPage(BpmnTaskPageSearchDTO dto) { + return null; + } + + + public List getTaskListFlatByProcessInstanceId(String processInstanceId, @Nullable String tenantId) { + return null; + } + + + public List getTaskListGroupByProcessInstanceId(String processInstanceId, @Nullable String tenantId) { + return null; + } + + + public List getActiveTasksByProcessInstanceId(String processInstanceId, String tenantId) { + return null; + } + + + public Boolean approveTask(BpmnTaskAuditDTO dto) { + return null; + } + + + public BatchOperationResultVO batchApproveTask(List dtos) { + return null; + } + + + public Boolean rejectTask(BpmnTaskAuditDTO dto) { + return null; + } + + + public BatchOperationResultVO batchRejectTask(List dtos) { + return null; + } + + + public Boolean transferTask(BpmnTaskTransferDTO dto) { + return null; + } + + + public BatchOperationResultVO batchTransferTask(List dtos) { + return null; + } + + + public Boolean commentTask(BpmnTaskCommentDTO dto) { + return null; + } + + + public Void addAttachment(BpmnTaskAttachmentDTO dto) { + return null; + } + + + public Boolean countersignTask(BpmnTaskCountersignDTO dto) { + return null; + } + + + public Boolean remindTask(BpmnTaskRemindDTO dto) { + return null; + } + + + public String createRobotTask(BpmnRobotTaskCreateDTO dto) { + return null; + } + + + public Boolean completeRobotTask(BpmnRobotTaskCompleteDTO dto) { + return null; + } + + + public String findTaskIdByInstanceIdAndPersonId(String processInstanceId, String personId) { + return null; + } + + + public Map findTaskIdByInstanceIdsAndPersonId(List processInstanceIds, String personId, BpmnFlowNodeType... filterTypes) { + return null; + } + + + public Void createVariable(String executionId, RestBpmnProcessVariable restVariable) { + return null; + } + + + public Void updateVariable(String executionId, RestBpmnProcessVariable restVariable) { + return null; + } + + + public Void deleteVariables(String executionId, String variableNames, String scope) { + return null; + } + + + public CategoryItemVO get(Long id) { + return null; + } + + + public List getByIds(List ids) { + return null; + } + + + public List getByValues(List values) { + return null; + } + + + public CategoryItemVO create(CategoryCreateDTO req) { + return null; + } + + + public CategoryItemVO update(CategoryUpdateDTO dto) { + return null; + } + + + public Boolean delete(Long id) { + return null; + } + + + public Boolean updateState(Long id, Boolean state) { + return null; + } + + + public List list(CategorySearchDTO dto) { + return null; + } + + + public BpmPageResult search(CategorySearchDTO dto) { + return null; + } + + + public Boolean createConfig(CategoryConfigCreateDTO dto) { + return null; + } + + + public Boolean deleteConfig(Long id) { + return null; + } + + + public BpmPageResult configSearch(CategoryConfigSearchDTO dto) { + return null; + } + + + public Boolean updateCategoryConfigType(Long id, String configType) { + return null; + } + + + public Boolean checkCategoryStatus(Long tenantId, String categoryCode) { + return null; + } + + + public List getDefaultButtons() { + return null; + } + + private T parseResult(Supplier> supplier, String operationType, Object... args) { + return parseResult(supplier, operationType, null, args); + } + + private T parseResult(Supplier> supplier, String operationType, Consumer> consumer, Object... args) { + log.info("{}-Param: {}", operationType, JSON.toJSONString(args)); + CommonResponse response = printLatency(supplier, operationType); + log.info("{}-Result: {}", operationType, JSON.toJSONString(response)); + if (!Objects.equals(HttpStatus.OK.value(), response.getCode())) { + if (consumer != null) { + consumer.accept(response); + } else { + throw new RuntimeException(response.getMsg()); + } + } + return response.getData(); + } + + public R printLatency(Supplier function, String optType) { + StopWatch stopWatch = new StopWatch(optType); + stopWatch.start(optType); + R r = function.get(); + stopWatch.stop(); + log.info(stopWatch.shortSummary()); + return r; + } +} From 7a5e5329b8ed95c83c2b75c3b562f94e570540fb Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 22 May 2024 17:09:04 +0800 Subject: [PATCH 005/210] =?UTF-8?q?update=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/service/WorkflowEngineServiceFacade.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java index 16e64ea30..70d7b2145 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java @@ -72,5 +72,6 @@ public class WorkflowEngineServiceFacade { } public Map getProcessVariablesSync() { + return null; } } From 86679f324054d1b44c8c09e6227c16dd49f3e285 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 27 May 2024 13:48:42 +0800 Subject: [PATCH 006/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/workflow-engine-spring-boot-starter/README.md b/workflow-engine-spring-boot-starter/README.md index b31b91b90..01842c64e 100644 --- a/workflow-engine-spring-boot-starter/README.md +++ b/workflow-engine-spring-boot-starter/README.md @@ -8,8 +8,19 @@ ### 功能点 - 包装监听 Workflow Engine 服务端所有的广播事件,业务方仅简单实现或继承指定类完成自己的业务逻辑即可,不再关注其他细节。 + - 业务可实现监听器: + 1. ProcessInstanceListener + 2. ProcessTaskListener + 3. ProcessActivityListener + 4. MessageNotificationListener - 内部与工作流的数据交互,也将异步解耦,确保在调用对端服务时,不会因为对端服务中止而失败。 + - 接口需要有分类: + 1. 部分接口仅支持同步调 + 2. 大部分接口支持同步和异步调用,异步调用则是利用 MQ 进行触发 + 3. 接口需要有调用限制的控制,并非搜有的使用方均可直接调用 + 4. 针对同步调用设计支持回调接口,供使用方自行处理 - 内部将主动监听 MQ 队列,避免因为顺序消费从而导致的队列阻塞。 + - 降级实现,只要能确保顺序消费把所有的异常情况都考虑到,不阻塞消费便无需该功能。 - 本地启动将不再主动消费容器环境中的 MQ 广播,避免本地异常消费。 - 包装引擎抛出的所有异常,不再由业务方判断各类异常 code,而由 starter 统一确定是否抛出异常。 From 2c20b69cb9cbde99649fc8abfded04e80e0979e4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 27 May 2024 17:00:03 +0800 Subject: [PATCH 007/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=B8=80=E4=BA=9B=E4=BC=AA=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/README.md | 4 +++- .../starter/WorkflowEngineProperties.java | 10 ++++++++ .../listener/MessageNotificationListener.java | 10 ++++++++ .../listener/ProcessActivityListener.java | 10 ++++++++ .../listener/ProcessInstanceListener.java | 19 +++++++++++++++ .../starter/listener/ProcessListener.java | 16 +++++++++++++ .../starter/listener/ProcessTaskListener.java | 10 ++++++++ .../consumer/InnerActivityEventListener.java | 2 ++ .../consumer/InnerNoticeEventListener.java | 23 ++++++++++++++++++- .../service/impl/AsynchronousService.java | 3 ++- 10 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java diff --git a/workflow-engine-spring-boot-starter/README.md b/workflow-engine-spring-boot-starter/README.md index 01842c64e..341f4682c 100644 --- a/workflow-engine-spring-boot-starter/README.md +++ b/workflow-engine-spring-boot-starter/README.md @@ -16,7 +16,9 @@ - 内部与工作流的数据交互,也将异步解耦,确保在调用对端服务时,不会因为对端服务中止而失败。 - 接口需要有分类: 1. 部分接口仅支持同步调 - 2. 大部分接口支持同步和异步调用,异步调用则是利用 MQ 进行触发 + 2. 大部分接口支持同步和异步调用, + - 异步调用则是利用 MQ 进行触发 + - 同步调用则是扫API包后,根据注解为某些接口生成 Feign 的代理类,而非让自动生成 Feign 代理类 3. 接口需要有调用限制的控制,并非搜有的使用方均可直接调用 4. 针对同步调用设计支持回调接口,供使用方自行处理 - 内部将主动监听 MQ 队列,避免因为顺序消费从而导致的队列阻塞。 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java index ea28fbffe..7af49e35a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java @@ -20,6 +20,8 @@ public class WorkflowEngineProperties { */ private Boolean localConsumer = false; + private Boolean autoAck = false; + public Boolean getManageable() { return manageable; } @@ -35,4 +37,12 @@ public class WorkflowEngineProperties { public void setLocalConsumer(Boolean localConsumer) { this.localConsumer = localConsumer; } + + public Boolean getAutoAck() { + return autoAck; + } + + public void setAutoAck(Boolean autoAck) { + this.autoAck = autoAck; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java new file mode 100644 index 000000000..615dd1cc0 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.listener; + +/** + * TODO + * + * @author wangli + * @since 2024/5/27 16:25 + */ +public interface MessageNotificationListener { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java new file mode 100644 index 000000000..0c3ee9f98 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.listener; + +/** + * TODO + * + * @author wangli + * @since 2024/5/27 16:25 + */ +public interface ProcessActivityListener { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java new file mode 100644 index 000000000..c9e882311 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java @@ -0,0 +1,19 @@ +package cn.axzo.workflow.starter.listener; + +/** + * TODO + * + * @author wangli + * @since 2024/5/27 16:20 + */ +public interface ProcessInstanceListener extends ProcessListener { + + void created(); + + void completed(); + + void deleted(); + + void created(); + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java new file mode 100644 index 000000000..71ddc7706 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java @@ -0,0 +1,16 @@ +package cn.axzo.workflow.starter.listener; + +/** + * TODO + * + * @author wangli + * @since 2024/5/27 16:26 + */ +public interface ProcessListener { + /** + * 入参来源于配置 + * + * @param auto + */ + void ack(Boolean auto); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java new file mode 100644 index 000000000..54754c930 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.listener; + +/** + * TODO + * + * @author wangli + * @since 2024/5/27 16:21 + */ +public interface ProcessTaskListener { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 99d389e0e..4708c5b3a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -20,4 +20,6 @@ public class InnerActivityEventListener { ProcessActivityEventEnum.PROCESS_ACTIVITY_TAKE.getEventCode(), ProcessActivityEventEnum.PROCESS_ACTIVITY_END.getEventCode() ); + + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java index 8fe2317e8..83d535a10 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; +import cn.axzo.workflow.starter.listener.MessageNotificationListener; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,7 +16,7 @@ import java.util.List; * @since 2024/5/21 15:53 */ public class InnerNoticeEventListener { - private final Logger log = LoggerFactory.getLogger(InnerNoticeEventListener.class); + private final static Logger log = LoggerFactory.getLogger(InnerNoticeEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( ProcessMessagePushEventEnum.PROCESS_PUSH_NOTICE.getEventCode(), ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING.getEventCode(), @@ -25,4 +26,24 @@ public class InnerNoticeEventListener { ProcessMessagePushEventEnum.PROCESS_CARBON_COPY_COMPLETE.getEventCode(), ProcessMessagePushEventEnum.PROCESS_PUSH_SMS.getEventCode() ); + + public static void main(String[] args) { + MessageNotificationListener listener = new MessageNotificationListener() { + public int hashCode() { + return super.hashCode(); + } + }; + + try { + // 最后业务节点的 started 事件,业务再做一个事情, + listener.hashCode(); + + // trigger 最后一个节点, + log.error(""); + } catch (Exception e) { + // 这个地方应该配置项:业务需要阻塞,忽略 + throw new RuntimeException(e); + } + + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java index 1f16e32a7..07fafdcf7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.service.impl; +import cn.axzo.workflow.starter.listener.ProcessListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; /** @@ -12,6 +13,6 @@ import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; * @author wangli * @since 2024/5/22 10:55 */ -public interface AsynchronousService { +public interface AsynchronousService extends ProcessListener { } From 0744014f64ca264e0a31c7c17ad64209cb3d4207 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 28 May 2024 16:59:38 +0800 Subject: [PATCH 008/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AF=B9=20Star?= =?UTF-8?q?ter=20=E4=B8=AD=E7=9A=84=E9=97=A8=E9=9D=A2=20API=20=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=8A=80=E6=9C=AF=E6=8E=A8=E6=BC=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + workflow-engine-server/pom.xml | 4 + .../WorkflowEngineAutoConfiguration.java | 8 ++ .../starter/api/WorkflowCoreService.java | 14 +++ .../annotation/EnableWorkflowClient.java | 29 +++++ .../starter/invoke/ComplexInvokeClient.java | 26 +++++ .../invoke/WorkflowEngineClientRegistrar.java | 100 ++++++++++++++++++ .../listener/ProcessInstanceListener.java | 2 - .../service/WorkflowEngineServiceFacade.java | 10 +- 9 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java diff --git a/pom.xml b/pom.xml index 5a548b7b3..275e50f9c 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,11 @@ workflow-engine-server ${project.version} + + cn.axzo.workflow + workflow-engine-spring-boot-starter + ${project.version} + cn.axzo.maokai maokai-api diff --git a/workflow-engine-server/pom.xml b/workflow-engine-server/pom.xml index a00a3b70c..cbe4dcf96 100644 --- a/workflow-engine-server/pom.xml +++ b/workflow-engine-server/pom.xml @@ -21,6 +21,10 @@ 3.25.0 + + cn.axzo.workflow + workflow-engine-spring-boot-starter + cn.axzo.framework axzo-web-spring-boot-starter diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java index a8be85786..c3c19fea0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java @@ -6,10 +6,13 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; +import cn.axzo.workflow.starter.common.annotation.EnableWorkflowClient; +import cn.axzo.workflow.starter.invoke.ComplexInvokeClient; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.axzo.workflow.starter.service.WorkflowEngineServiceFacade; +import feign.Client; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; @@ -37,6 +40,7 @@ import java.util.function.Consumer; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineProperties.class) +@EnableWorkflowClient public class WorkflowEngineAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineAutoConfiguration.class); @@ -55,6 +59,10 @@ public class WorkflowEngineAutoConfiguration { return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineProperties); } + @Bean + public Client ComplexInvokeClient() { + return new ComplexInvokeClient(); + } /** * 客户端 RPC Retry 事件生产者 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java new file mode 100644 index 000000000..93f09fe3a --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -0,0 +1,14 @@ +package cn.axzo.workflow.starter.api; + +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; + +/** + * 模拟生成的受限访问的接口定义 + * + * @author wangli + * @since 2024/5/28 16:12 + */ +public interface WorkflowCoreService { + + String createProcessInstance(BpmnProcessInstanceCreateDTO dto); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java new file mode 100644 index 000000000..7b8375529 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java @@ -0,0 +1,29 @@ +package cn.axzo.workflow.starter.common.annotation; + +import cn.axzo.workflow.starter.invoke.WorkflowEngineClientRegistrar; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * TODO + * + * @author wangli + * @since 2024/5/28 16:27 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +@Import(WorkflowEngineClientRegistrar.class) +public @interface EnableWorkflowClient { + + String[] basePackages() default {"cn.axzo.workflow.starter.api"}; + + String name() default "workflow-engine-client"; + + String url() default "${axzo.service.workflow-engine:workflow-engine:8080}"; +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java new file mode 100644 index 000000000..cccc04ee9 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java @@ -0,0 +1,26 @@ +package cn.axzo.workflow.starter.invoke; + +import feign.Client; +import feign.Request; +import feign.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * TODO + * + * @author wangli + * @since 2024/5/28 15:23 + */ +public class ComplexInvokeClient implements Client { + + private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); + + @Override + public Response execute(Request request, Request.Options options) throws IOException { + log.info("ComplexInvokeClient execute"); + return null; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java new file mode 100644 index 000000000..83d113275 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java @@ -0,0 +1,100 @@ +package cn.axzo.workflow.starter.invoke; + +import cn.axzo.workflow.starter.common.annotation.EnableWorkflowClient; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * TODO + * + * @author wangli + * @since 2024/5/28 16:18 + */ +public class WorkflowEngineClientRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { + + private ResourceLoader resourceLoader; + + private Environment environment; + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + LinkedHashSet candidateComponents = new LinkedHashSet<>(); + ClassPathScanningCandidateComponentProvider scanner = getScanner(); + scanner.setResourceLoader(this.resourceLoader); + Set basePackages = getBasePackages(metadata); + for (String basePackage : basePackages) { + candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); + } + + for (BeanDefinition candidateComponent : candidateComponents) { + if (candidateComponent instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; + AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); + Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); + + Map attributes = new HashMap<>(); + + registerWorkflowEngineClient(registry, annotationMetadata, attributes); + } + } + } + + private void registerWorkflowEngineClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) { + + } + + protected ClassPathScanningCandidateComponentProvider getScanner() { + return new ClassPathScanningCandidateComponentProvider(false, this.environment) { + @Override + protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { + boolean isCandidate = false; + if (beanDefinition.getMetadata().isIndependent()) { + if (!beanDefinition.getMetadata().isAnnotation()) { + isCandidate = true; + } + } + return isCandidate; + } + }; + } + + protected Set getBasePackages(AnnotationMetadata metadata) { + Map attributes = metadata.getAnnotationAttributes(EnableWorkflowClient.class.getCanonicalName()); + + Set basePackages = new HashSet<>(); + for (String pkg : (String[]) attributes.get("basePackages")) { + if (StringUtils.hasText(pkg)) { + basePackages.add(pkg); + } + } + + return basePackages; + } + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java index c9e882311..4643d4e0a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java @@ -14,6 +14,4 @@ public interface ProcessInstanceListener extends ProcessListener { void deleted(); - void created(); - } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java index 70d7b2145..559f6aaf2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java @@ -7,8 +7,6 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.starter.WorkflowEngineProperties; import cn.axzo.workflow.starter.common.exception.CreateProcessInstanceException; -import cn.axzo.workflow.starter.service.impl.AsynchronousService; -import cn.axzo.workflow.starter.service.impl.SynchronousService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,15 +22,11 @@ import java.util.Map; public class WorkflowEngineServiceFacade { private final Logger log = LoggerFactory.getLogger(WorkflowEngineServiceFacade.class); private final EventProducer workflowEngineClientEventProducer; - private final AsynchronousService asynchronousService; - private final SynchronousService synchronousService; private final WorkflowEngineProperties workflowEngineProperties; - public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, AsynchronousService asynchronousService, SynchronousService synchronousService, + public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, WorkflowEngineProperties workflowEngineProperties) { this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; - this.asynchronousService = asynchronousService; - this.synchronousService = synchronousService; this.workflowEngineProperties = workflowEngineProperties; } @@ -46,7 +40,7 @@ public class WorkflowEngineServiceFacade { * @throws {@link CreateProcessInstanceException} 创建流程实例失败时抛出异常 */ public String createProcessInstanceSync(BpmnProcessInstanceCreateDTO dto) { - return synchronousService.createProcessInstance(dto); + return null; } /** From 8ab05b18c9bffc5a45fa92b3d9a815dacf89cee9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 28 May 2024 18:11:17 +0800 Subject: [PATCH 009/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AF=B9=20Star?= =?UTF-8?q?ter=20=E4=B8=AD=E7=9A=84=E9=97=A8=E9=9D=A2=20API=20=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=8A=80=E6=9C=AF=E6=8E=A8=E6=BC=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 3 + .../WorkflowEngineAutoConfiguration.java | 4 +- .../starter/api/WorkflowCoreService.java | 2 + ...t.java => EnableWorkflowEngineClient.java} | 2 +- .../annotation/WorkflowEngineClient.java | 21 ++++ .../invoke/WorkflowEngineClientRegistrar.java | 110 ++++++++++++++++-- 6 files changed, 127 insertions(+), 15 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/{EnableWorkflowClient.java => EnableWorkflowEngineClient.java} (94%) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 7628389ee..a015ac947 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -8,6 +8,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; +import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.azxo.framework.common.model.CommonResponse; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; @@ -58,6 +59,8 @@ public class TestController { private ProcessInstanceApi processInstanceApi; @Autowired private BpmnProcessInstanceService bpmnProcessInstanceService; + @Autowired + private WorkflowCoreService workflowCoreService; @RepeatSubmit @GetMapping("/test") diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java index c3c19fea0..e605673a2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java @@ -6,7 +6,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; -import cn.axzo.workflow.starter.common.annotation.EnableWorkflowClient; +import cn.axzo.workflow.starter.common.annotation.EnableWorkflowEngineClient; import cn.axzo.workflow.starter.invoke.ComplexInvokeClient; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; @@ -40,7 +40,7 @@ import java.util.function.Consumer; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineProperties.class) -@EnableWorkflowClient +@EnableWorkflowEngineClient public class WorkflowEngineAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineAutoConfiguration.class); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 93f09fe3a..bd9222fd3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.starter.common.annotation.WorkflowEngineClient; /** * 模拟生成的受限访问的接口定义 @@ -8,6 +9,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre * @author wangli * @since 2024/5/28 16:12 */ +@WorkflowEngineClient public interface WorkflowCoreService { String createProcessInstance(BpmnProcessInstanceCreateDTO dto); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java similarity index 94% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java index 7b8375529..11bf6c09e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java @@ -19,7 +19,7 @@ import java.lang.annotation.Target; @Target(ElementType.TYPE) @Documented @Import(WorkflowEngineClientRegistrar.class) -public @interface EnableWorkflowClient { +public @interface EnableWorkflowEngineClient { String[] basePackages() default {"cn.axzo.workflow.starter.api"}; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java new file mode 100644 index 000000000..6b1c7376f --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java @@ -0,0 +1,21 @@ +package cn.axzo.workflow.starter.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * TODO + * + * @author wangli + * @since 2024/5/28 17:16 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface WorkflowEngineClient { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java index 83d113275..6e56c5764 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java @@ -1,9 +1,19 @@ package cn.axzo.workflow.starter.invoke; -import cn.axzo.workflow.starter.common.annotation.EnableWorkflowClient; +import cn.axzo.workflow.starter.common.annotation.EnableWorkflowEngineClient; +import cn.axzo.workflow.starter.common.annotation.WorkflowEngineClient; +import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.beans.factory.config.BeanExpressionResolver; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.cloud.openfeign.FeignClientFactoryBean; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; @@ -11,10 +21,12 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.Assert; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; -import java.util.HashMap; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; @@ -47,6 +59,7 @@ public class WorkflowEngineClientRegistrar implements ImportBeanDefinitionRegist LinkedHashSet candidateComponents = new LinkedHashSet<>(); ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); + scanner.addIncludeFilter(new AnnotationTypeFilter(WorkflowEngineClient.class)); Set basePackages = getBasePackages(metadata); for (String basePackage : basePackages) { candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); @@ -54,19 +67,78 @@ public class WorkflowEngineClientRegistrar implements ImportBeanDefinitionRegist for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { - AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; - AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); - Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); - - Map attributes = new HashMap<>(); - - registerWorkflowEngineClient(registry, annotationMetadata, attributes); + Map attributes = metadata.getAnnotationAttributes(WorkflowEngineClient.class.getName()); + registerWorkflowEngineClient(registry, metadata, attributes); } } } - private void registerWorkflowEngineClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) { + private void registerWorkflowEngineClient(BeanDefinitionRegistry registry, AnnotationMetadata metadata, Map attributes) { + String className = metadata.getClassName(); + Class clazz = ClassUtils.resolveClassName(className, null); + ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory + ? (ConfigurableBeanFactory) registry : null; + String contextId = "workflow-engine-client"; + FeignClientFactoryBean factoryBean = new FeignClientFactoryBean(); + factoryBean.setBeanFactory(beanFactory); + factoryBean.setName(contextId); + factoryBean.setContextId(contextId); + factoryBean.setType(clazz); + BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> { + factoryBean.setUrl(getUrl(beanFactory, attributes)); + factoryBean.setPath(getPath(beanFactory, attributes)); + return factoryBean.getObject(); + }); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + definition.setLazyInit(true); + AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); + beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className); + beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean); + + beanDefinition.setPrimary(true); + + String[] qualifiers = new String[]{contextId}; + + BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers); + BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); + } + + private String getPath(ConfigurableBeanFactory beanFactory, Map attributes) { + String path = resolve(beanFactory, (String) attributes.get("path")); + return getPath(path); + } + + static String getPath(String path) { + if (StringUtils.hasText(path)) { + path = path.trim(); + if (!path.startsWith("/")) { + path = "/" + path; + } + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + } + return path; + } + + private String getUrl(ConfigurableBeanFactory beanFactory, Map attributes) { + String url = resolve(beanFactory, (String) attributes.get("url")); + return getUrl(url); + } + + static String getUrl(String url) { + if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) { + if (!url.contains("://")) { + url = "http://" + url; + } + try { + new URL(url); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(url + " is malformed", e); + } + } + return url; } protected ClassPathScanningCandidateComponentProvider getScanner() { @@ -85,7 +157,7 @@ public class WorkflowEngineClientRegistrar implements ImportBeanDefinitionRegist } protected Set getBasePackages(AnnotationMetadata metadata) { - Map attributes = metadata.getAnnotationAttributes(EnableWorkflowClient.class.getCanonicalName()); + Map attributes = metadata.getAnnotationAttributes(EnableWorkflowEngineClient.class.getCanonicalName()); Set basePackages = new HashSet<>(); for (String pkg : (String[]) attributes.get("basePackages")) { @@ -97,4 +169,18 @@ public class WorkflowEngineClientRegistrar implements ImportBeanDefinitionRegist return basePackages; } + private String resolve(ConfigurableBeanFactory beanFactory, String value) { + if (StringUtils.hasText(value)) { + if (beanFactory == null) { + return this.environment.resolvePlaceholders(value); + } + BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver(); + String resolved = beanFactory.resolveEmbeddedValue(value); + if (resolver == null) { + return resolved; + } + return String.valueOf(resolver.evaluate(resolved, new BeanExpressionContext(beanFactory, null))); + } + return value; + } } From c9f82eb3317f886888292ddc2f1539f9bc8b84ff Mon Sep 17 00:00:00 2001 From: wangli Date: Wed, 29 May 2024 00:06:25 +0800 Subject: [PATCH 010/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AF=B9=20Star?= =?UTF-8?q?ter=20=E5=90=8C=E6=AD=A5=E5=BC=82=E6=AD=A5=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=8A=80=E6=9C=AF=E6=8E=A8=E6=BC=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...rkflowEngineStarterAutoConfiguration.java} | 21 +- ...a => WorkflowEngineStarterProperties.java} | 4 +- .../starter/api/WorkflowCoreService.java | 12 +- .../EnableWorkflowEngineClient.java | 29 --- .../annotation/WorkflowEngineClient.java | 21 -- .../exception/AsyncNotSupportException.java | 2 +- .../CreateProcessInstanceException.java | 2 +- .../ManagementDisabledException.java | 2 +- ...va => WorkflowEngineStarterException.java} | 2 +- .../invoke/WorkflowEngineClientRegistrar.java | 186 ------------------ .../WorkflowEngineStarterConfiguration.java | 20 ++ .../service/WorkflowEngineServiceFacade.java | 8 +- .../main/resources/META-INF/spring.factories | 2 +- 13 files changed, 48 insertions(+), 263 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{WorkflowEngineAutoConfiguration.java => WorkflowEngineStarterAutoConfiguration.java} (92%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{WorkflowEngineProperties.java => WorkflowEngineStarterProperties.java} (89%) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/{WorkflowEngineClientException.java => WorkflowEngineStarterException.java} (62%) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java similarity index 92% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index e605673a2..b8ecb0fe3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -6,13 +6,11 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; -import cn.axzo.workflow.starter.common.annotation.EnableWorkflowEngineClient; -import cn.axzo.workflow.starter.invoke.ComplexInvokeClient; +import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.axzo.workflow.starter.service.WorkflowEngineServiceFacade; -import feign.Client; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; @@ -23,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @@ -39,11 +38,11 @@ import java.util.function.Consumer; * @since 2024/5/21 11:47 */ @Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties(WorkflowEngineProperties.class) -@EnableWorkflowEngineClient -public class WorkflowEngineAutoConfiguration { +@EnableConfigurationProperties(WorkflowEngineStarterProperties.class) +@EnableFeignClients(clients = {WorkflowCoreService.class}) +public class WorkflowEngineStarterAutoConfiguration { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineAutoConfiguration.class); + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); private static final String DEFAULT_MODULE = "workflowEngine"; private static final String DEFAULT_EVENT = "topic_workflow_engine"; @@ -55,14 +54,10 @@ public class WorkflowEngineAutoConfiguration { @Bean public WorkflowEngineServiceFacade workflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, - WorkflowEngineProperties workflowEngineProperties) { - return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineProperties); + WorkflowEngineStarterProperties workflowEngineStarterProperties) { + return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineStarterProperties); } - @Bean - public Client ComplexInvokeClient() { - return new ComplexInvokeClient(); - } /** * 客户端 RPC Retry 事件生产者 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java similarity index 89% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 7af49e35a..5980487de 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -8,8 +8,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author wangli * @since 2024/5/21 15:24 */ -@ConfigurationProperties(prefix = "workflow.engine.client") -public class WorkflowEngineProperties { +@ConfigurationProperties(prefix = "workflow.engine.starter") +public class WorkflowEngineStarterProperties { /** * 是否可管理 */ diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index bd9222fd3..f3b0d08bd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,7 +1,12 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.starter.common.annotation.WorkflowEngineClient; +import cn.axzo.workflow.starter.invoke.WorkflowEngineStarterConfiguration; +import cn.azxo.framework.common.model.CommonResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; /** * 模拟生成的受限访问的接口定义 @@ -9,8 +14,9 @@ import cn.axzo.workflow.starter.common.annotation.WorkflowEngineClient; * @author wangli * @since 2024/5/28 16:12 */ -@WorkflowEngineClient +@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = {WorkflowEngineStarterConfiguration.class}) public interface WorkflowCoreService { - String createProcessInstance(BpmnProcessInstanceCreateDTO dto); + @PostMapping("/api/process/instance/create") + CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java deleted file mode 100644 index 11bf6c09e..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/EnableWorkflowEngineClient.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.axzo.workflow.starter.common.annotation; - -import cn.axzo.workflow.starter.invoke.WorkflowEngineClientRegistrar; -import org.springframework.context.annotation.Import; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * TODO - * - * @author wangli - * @since 2024/5/28 16:27 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Documented -@Import(WorkflowEngineClientRegistrar.class) -public @interface EnableWorkflowEngineClient { - - String[] basePackages() default {"cn.axzo.workflow.starter.api"}; - - String name() default "workflow-engine-client"; - - String url() default "${axzo.service.workflow-engine:workflow-engine:8080}"; -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java deleted file mode 100644 index 6b1c7376f..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/annotation/WorkflowEngineClient.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.axzo.workflow.starter.common.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * TODO - * - * @author wangli - * @since 2024/5/28 17:16 - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -public @interface WorkflowEngineClient { -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java index b917a4225..23c74cdd5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java @@ -6,5 +6,5 @@ package cn.axzo.workflow.starter.common.exception; * @author wangli * @since 2024/5/21 17:59 */ -public class AsyncNotSupportException extends WorkflowEngineClientException { +public class AsyncNotSupportException extends WorkflowEngineStarterException { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java index 1f697251d..45d3d0898 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java @@ -6,5 +6,5 @@ package cn.axzo.workflow.starter.common.exception; * @author wangli * @since 2024/5/22 13:41 */ -public class CreateProcessInstanceException extends WorkflowEngineClientException { +public class CreateProcessInstanceException extends WorkflowEngineStarterException { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java index 0a14efd7d..7981f16bb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java @@ -6,5 +6,5 @@ package cn.axzo.workflow.starter.common.exception; * @author wangli * @since 2024/5/21 17:59 */ -public class ManagementDisabledException extends WorkflowEngineClientException { +public class ManagementDisabledException extends WorkflowEngineStarterException { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java similarity index 62% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java index 230990ec7..c8c59d456 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineClientException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java @@ -6,5 +6,5 @@ package cn.axzo.workflow.starter.common.exception; * @author wangli * @since 2024/5/21 17:57 */ -public class WorkflowEngineClientException extends RuntimeException { +public class WorkflowEngineStarterException extends RuntimeException { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java deleted file mode 100644 index 6e56c5764..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineClientRegistrar.java +++ /dev/null @@ -1,186 +0,0 @@ -package cn.axzo.workflow.starter.invoke; - -import cn.axzo.workflow.starter.common.annotation.EnableWorkflowEngineClient; -import cn.axzo.workflow.starter.common.annotation.WorkflowEngineClient; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.BeanExpressionContext; -import org.springframework.beans.factory.config.BeanExpressionResolver; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.cloud.openfeign.FeignClientFactoryBean; -import org.springframework.context.EnvironmentAware; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -/** - * TODO - * - * @author wangli - * @since 2024/5/28 16:18 - */ -public class WorkflowEngineClientRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { - - private ResourceLoader resourceLoader; - - private Environment environment; - - @Override - public void setEnvironment(Environment environment) { - this.environment = environment; - } - - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - @Override - public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { - LinkedHashSet candidateComponents = new LinkedHashSet<>(); - ClassPathScanningCandidateComponentProvider scanner = getScanner(); - scanner.setResourceLoader(this.resourceLoader); - scanner.addIncludeFilter(new AnnotationTypeFilter(WorkflowEngineClient.class)); - Set basePackages = getBasePackages(metadata); - for (String basePackage : basePackages) { - candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); - } - - for (BeanDefinition candidateComponent : candidateComponents) { - if (candidateComponent instanceof AnnotatedBeanDefinition) { - Map attributes = metadata.getAnnotationAttributes(WorkflowEngineClient.class.getName()); - registerWorkflowEngineClient(registry, metadata, attributes); - } - } - } - - private void registerWorkflowEngineClient(BeanDefinitionRegistry registry, AnnotationMetadata metadata, Map attributes) { - String className = metadata.getClassName(); - Class clazz = ClassUtils.resolveClassName(className, null); - ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory - ? (ConfigurableBeanFactory) registry : null; - String contextId = "workflow-engine-client"; - FeignClientFactoryBean factoryBean = new FeignClientFactoryBean(); - factoryBean.setBeanFactory(beanFactory); - factoryBean.setName(contextId); - factoryBean.setContextId(contextId); - factoryBean.setType(clazz); - BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> { - factoryBean.setUrl(getUrl(beanFactory, attributes)); - factoryBean.setPath(getPath(beanFactory, attributes)); - return factoryBean.getObject(); - }); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - definition.setLazyInit(true); - - AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); - beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className); - beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean); - - beanDefinition.setPrimary(true); - - String[] qualifiers = new String[]{contextId}; - - BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers); - BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); - } - - private String getPath(ConfigurableBeanFactory beanFactory, Map attributes) { - String path = resolve(beanFactory, (String) attributes.get("path")); - return getPath(path); - } - - static String getPath(String path) { - if (StringUtils.hasText(path)) { - path = path.trim(); - if (!path.startsWith("/")) { - path = "/" + path; - } - if (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - } - return path; - } - - private String getUrl(ConfigurableBeanFactory beanFactory, Map attributes) { - String url = resolve(beanFactory, (String) attributes.get("url")); - return getUrl(url); - } - - static String getUrl(String url) { - if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) { - if (!url.contains("://")) { - url = "http://" + url; - } - try { - new URL(url); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(url + " is malformed", e); - } - } - return url; - } - - protected ClassPathScanningCandidateComponentProvider getScanner() { - return new ClassPathScanningCandidateComponentProvider(false, this.environment) { - @Override - protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { - boolean isCandidate = false; - if (beanDefinition.getMetadata().isIndependent()) { - if (!beanDefinition.getMetadata().isAnnotation()) { - isCandidate = true; - } - } - return isCandidate; - } - }; - } - - protected Set getBasePackages(AnnotationMetadata metadata) { - Map attributes = metadata.getAnnotationAttributes(EnableWorkflowEngineClient.class.getCanonicalName()); - - Set basePackages = new HashSet<>(); - for (String pkg : (String[]) attributes.get("basePackages")) { - if (StringUtils.hasText(pkg)) { - basePackages.add(pkg); - } - } - - return basePackages; - } - - private String resolve(ConfigurableBeanFactory beanFactory, String value) { - if (StringUtils.hasText(value)) { - if (beanFactory == null) { - return this.environment.resolvePlaceholders(value); - } - BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver(); - String resolved = beanFactory.resolveEmbeddedValue(value); - if (resolver == null) { - return resolved; - } - return String.valueOf(resolver.evaluate(resolved, new BeanExpressionContext(beanFactory, null))); - } - return value; - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java new file mode 100644 index 000000000..534c31692 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java @@ -0,0 +1,20 @@ +package cn.axzo.workflow.starter.invoke; + +import feign.Client; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * TODO + * + * @author wangli + * @since 2024/5/28 23:17 + */ +@Configuration(proxyBeanMethods = false) +public class WorkflowEngineStarterConfiguration { + + @Bean + public Client complexInvokeClient() { + return new ComplexInvokeClient(); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java index 559f6aaf2..f5a2528c6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java @@ -5,7 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbo import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.starter.WorkflowEngineProperties; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.common.exception.CreateProcessInstanceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,12 +22,12 @@ import java.util.Map; public class WorkflowEngineServiceFacade { private final Logger log = LoggerFactory.getLogger(WorkflowEngineServiceFacade.class); private final EventProducer workflowEngineClientEventProducer; - private final WorkflowEngineProperties workflowEngineProperties; + private final WorkflowEngineStarterProperties workflowEngineStarterProperties; public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, - WorkflowEngineProperties workflowEngineProperties) { + WorkflowEngineStarterProperties workflowEngineStarterProperties) { this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; - this.workflowEngineProperties = workflowEngineProperties; + this.workflowEngineStarterProperties = workflowEngineStarterProperties; } /** diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories index 36c761db5..272293ebe 100644 --- a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - cn.axzo.workflow.starter.WorkflowEngineAutoConfiguration + cn.axzo.workflow.starter.WorkflowEngineStarterAutoConfiguration From 0fd965f1d5d223a7d701205ca7dde92594d6beb0 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 May 2024 10:43:12 +0800 Subject: [PATCH 011/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E4=B8=BA=20Starter=20=E6=96=B0=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3=E8=BF=9B=E8=A1=8C=20Feign=20?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 13 +++++++++++++ .../WorkflowEngineStarterProperties.java | 16 ++++++++++++++++ .../starter/api/WorkflowCoreService.java | 2 +- .../starter/common/enums/RpcInvokeModeEnum.java | 12 ++++++++++++ .../starter/invoke/ComplexInvokeClient.java | 4 ++++ .../WorkflowEngineStarterConfiguration.java | 17 ++++++++++++++--- 6 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index a015ac947..4f8b71434 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -1,8 +1,11 @@ package cn.axzo.workflow.server.controller.web; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; +import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; @@ -127,4 +130,14 @@ public class TestController { return CommonResponse.success(true); } + @GetMapping("/test5") + public CommonResponse test5() { + BpmnProcessInstanceCreateDTO dto = new BpmnProcessInstanceCreateDTO(); + dto.setProcessDefinitionKey("1"); + dto.setCooperationOrg(new CooperationOrgDTO()); + dto.setBusinessKey("businessKey"); + dto.setInitiator(new BpmnTaskDelegateAssigner()); + workflowCoreService.createProcessInstance(dto); + return CommonResponse.success(true); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 5980487de..569de0dce 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -1,7 +1,10 @@ package cn.axzo.workflow.starter; +import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; +import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; + /** * Workflow Engine Starter Properties * @@ -20,6 +23,11 @@ public class WorkflowEngineStarterProperties { */ private Boolean localConsumer = false; + /** + * 方法调用默认采用的模式 + */ + private RpcInvokeModeEnum invokeMode = ASYNC; + private Boolean autoAck = false; public Boolean getManageable() { @@ -38,6 +46,14 @@ public class WorkflowEngineStarterProperties { this.localConsumer = localConsumer; } + public RpcInvokeModeEnum getInvokeMode() { + return invokeMode; + } + + public void setInvokeMode(RpcInvokeModeEnum invokeMode) { + this.invokeMode = invokeMode; + } + public Boolean getAutoAck() { return autoAck; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index f3b0d08bd..0e8b9d1da 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RequestBody; * @author wangli * @since 2024/5/28 16:12 */ -@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = {WorkflowEngineStarterConfiguration.class}) +@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterConfiguration.class) public interface WorkflowCoreService { @PostMapping("/api/process/instance/create") diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java new file mode 100644 index 000000000..1e6c0e778 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java @@ -0,0 +1,12 @@ +package cn.axzo.workflow.starter.common.enums; + +/** + * TODO + * + * @author wangli + * @since 2024/5/29 10:27 + */ +public enum RpcInvokeModeEnum { + SYNC, + ASYNC, +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java index cccc04ee9..68b186def 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java @@ -7,6 +7,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Collection; +import java.util.Map; /** * TODO @@ -21,6 +23,8 @@ public class ComplexInvokeClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { log.info("ComplexInvokeClient execute"); + Map> headers = request.headers(); + headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); return null; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java index 534c31692..3ed78fbcc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java @@ -1,20 +1,31 @@ package cn.axzo.workflow.starter.invoke; import feign.Client; +import feign.RequestInterceptor; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; /** - * TODO + * Starter Feign Client 的自定义的配置 * * @author wangli * @since 2024/5/28 23:17 */ -@Configuration(proxyBeanMethods = false) public class WorkflowEngineStarterConfiguration { + private static final String STARTER_INVOKE_MODE = "Workflow-Engine-Starter-Invoke-Mode"; @Bean public Client complexInvokeClient() { return new ComplexInvokeClient(); } + + @Bean + public RequestInterceptor complexInvokeRequestInterceptor(Environment environment) { + return template -> { + template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); + template.header(STARTER_INVOKE_MODE, environment.getProperty("workflow.engine.starter.invoke-mode")); + }; + } } From 2d2ecd9da16dd3628a1e11134213ca6983f25a75 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 May 2024 11:40:25 +0800 Subject: [PATCH 012/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E6=88=90=20Starter=20Feign=20Client=20=E7=9A=84=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=EF=BC=8C=E5=B7=B2=E6=94=AF=E6=8C=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=BC=82=E6=AD=A5=E7=9A=84=E6=A0=87=E8=AF=86=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterProperties.java | 4 +-- .../common/constant/StarterConstants.java | 11 +++++++ .../exception/AsyncNotSupportException.java | 3 ++ .../CreateProcessInstanceException.java | 3 ++ .../ManagementDisabledException.java | 3 ++ .../WorkflowEngineStarterException.java | 4 +++ .../starter/invoke/ComplexInvokeClient.java | 32 +++++++++++++++++++ .../WorkflowEngineStarterConfiguration.java | 11 ++++--- 8 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 569de0dce..099bd18b8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -3,7 +3,7 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; -import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; /** * Workflow Engine Starter Properties @@ -26,7 +26,7 @@ public class WorkflowEngineStarterProperties { /** * 方法调用默认采用的模式 */ - private RpcInvokeModeEnum invokeMode = ASYNC; + private RpcInvokeModeEnum invokeMode = SYNC; private Boolean autoAck = false; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java new file mode 100644 index 000000000..d186f8765 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java @@ -0,0 +1,11 @@ +package cn.axzo.workflow.starter.common.constant; + +/** + * Starter 常量类 + * + * @author wangli + * @since 2024/5/29 11:13 + */ +public interface StarterConstants { + String STARTER_INVOKE_MODE = "Workflow-Engine-Starter-Invoke-Mode"; +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java index 23c74cdd5..f129865b5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java @@ -7,4 +7,7 @@ package cn.axzo.workflow.starter.common.exception; * @since 2024/5/21 17:59 */ public class AsyncNotSupportException extends WorkflowEngineStarterException { + public AsyncNotSupportException(String message) { + super(message); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java index 45d3d0898..d3cda1def 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java @@ -7,4 +7,7 @@ package cn.axzo.workflow.starter.common.exception; * @since 2024/5/22 13:41 */ public class CreateProcessInstanceException extends WorkflowEngineStarterException { + public CreateProcessInstanceException(String message) { + super(message); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java index 7981f16bb..c7701dcfe 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java @@ -7,4 +7,7 @@ package cn.axzo.workflow.starter.common.exception; * @since 2024/5/21 17:59 */ public class ManagementDisabledException extends WorkflowEngineStarterException { + public ManagementDisabledException(String message) { + super(message); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java index c8c59d456..d74115e10 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java @@ -7,4 +7,8 @@ package cn.axzo.workflow.starter.common.exception; * @since 2024/5/21 17:57 */ public class WorkflowEngineStarterException extends RuntimeException { + + public WorkflowEngineStarterException(String message) { + super(message); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java index 68b186def..1fa94e241 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java @@ -1,5 +1,8 @@ package cn.axzo.workflow.starter.invoke; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; +import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import feign.Client; import feign.Request; import feign.Response; @@ -8,7 +11,12 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collection; +import java.util.Collections; import java.util.Map; +import java.util.Objects; + +import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; +import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; /** * TODO @@ -19,12 +27,36 @@ import java.util.Map; public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); + private final WorkflowEngineStarterProperties starterProperties; + private final Client feignClient; + + public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, Client feignClient) { + this.starterProperties = starterProperties; + this.feignClient = feignClient; + } @Override public Response execute(Request request, Request.Options options) throws IOException { log.info("ComplexInvokeClient execute"); + RpcInvokeModeEnum invokeMode = getInvokeMode(request); + if (Objects.equals(SYNC, invokeMode)) { + return feignClient.execute(request, options); + } + + Map> headers = request.headers(); headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); return null; } + + private RpcInvokeModeEnum getInvokeMode(Request request) { + Collection invokeModel = request.headers().getOrDefault(STARTER_INVOKE_MODE, + Collections.singletonList(starterProperties.getInvokeMode().name())); + if (invokeModel == null || invokeModel.isEmpty()) { + return starterProperties.getInvokeMode(); + } else if (invokeModel.size() > 1) { + throw new WorkflowEngineStarterException("Multiple invoke mode is not supported"); + } + return RpcInvokeModeEnum.valueOf(invokeModel.iterator().next()); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java index 3ed78fbcc..25170c315 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java @@ -1,11 +1,13 @@ package cn.axzo.workflow.starter.invoke; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import feign.Client; import feign.RequestInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; +import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; /** * Starter Feign Client 的自定义的配置 @@ -14,18 +16,17 @@ import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_S * @since 2024/5/28 23:17 */ public class WorkflowEngineStarterConfiguration { - private static final String STARTER_INVOKE_MODE = "Workflow-Engine-Starter-Invoke-Mode"; @Bean - public Client complexInvokeClient() { - return new ComplexInvokeClient(); + public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, Client feignClient) { + return new ComplexInvokeClient(starterProperties, feignClient); } @Bean - public RequestInterceptor complexInvokeRequestInterceptor(Environment environment) { + public RequestInterceptor complexInvokeRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment) { return template -> { template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); - template.header(STARTER_INVOKE_MODE, environment.getProperty("workflow.engine.starter.invoke-mode")); + template.header(STARTER_INVOKE_MODE, starterProperties.getInvokeMode().name()); }; } } From 5c6e47b4bf791bdb756c962605add6e5de5a4537 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 May 2024 13:36:07 +0800 Subject: [PATCH 013/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=B8=80=E4=BA=9B=E7=B1=BB=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/starter/api/WorkflowCoreService.java | 2 +- .../starter/{invoke => feign/ext}/ComplexInvokeClient.java | 6 ++++-- .../ext}/WorkflowEngineStarterConfiguration.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{invoke => feign/ext}/ComplexInvokeClient.java (90%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{invoke => feign/ext}/WorkflowEngineStarterConfiguration.java (84%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 0e8b9d1da..c8ea69cd3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,7 +1,7 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.starter.invoke.WorkflowEngineStarterConfiguration; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterConfiguration; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java similarity index 90% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 1fa94e241..2b03d99b4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.invoke; +package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; @@ -19,7 +19,9 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_ import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; /** - * TODO + * 适用于 Starter 中复合型的 FeignClient 实现 + *

+ * 如果使用方调用的服务方法是同步,则使用原生的 FeignClient 实现, 否则通过 MQ 事件解耦请求 * * @author wangli * @since 2024/5/28 15:23 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java similarity index 84% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java index 25170c315..83778f979 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/invoke/WorkflowEngineStarterConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.invoke; +package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import feign.Client; @@ -23,7 +23,7 @@ public class WorkflowEngineStarterConfiguration { } @Bean - public RequestInterceptor complexInvokeRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment) { + public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment) { return template -> { template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); template.header(STARTER_INVOKE_MODE, starterProperties.getInvokeMode().name()); From 85b305ba5e7253c1f27e83b5650edad1e138230f Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 29 May 2024 14:23:30 +0800 Subject: [PATCH 014/210] =?UTF-8?q?update=20-=20REQ-2516-=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=AF=B9=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E6=9A=B4=E9=9C=B2=E7=9A=84=E6=8E=A5=E5=8F=A3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 11 + workflow-auto-gen/pom.xml | 29 +++ .../generate/BaseCodeGenProcessor.java | 16 ++ .../workflow/generate/CodeGenProcessor.java | 31 +++ .../generate/CodeGenProcessorRegistry.java | 43 ++++ .../axzo/workflow/generate/GenCodeInfo.java | 68 ++++++ .../generate/GenJavaSourceFileUtils.java | 45 ++++ .../generate/GenServiceProcessor.java | 87 ++++++++ .../generate/ProcessingEnvironmentHolder.java | 17 ++ .../WorkflowExposeApiGenProcessor.java | 128 +++++++++++ .../generate/annotition/GenService.java | 21 ++ .../generate/annotition/Management.java | 10 + .../javax.annotation.processing.Processor | 1 + workflow-engine-api/pom.xml | 5 + .../client/annotation/Management.java | 10 - .../client/feign/bpmn/ProcessActivityApi.java | 2 + .../feign/bpmn/ProcessDefinitionApi.java | 2 - .../client/feign/bpmn/ProcessInstanceApi.java | 2 + .../client/feign/bpmn/ProcessJobApi.java | 2 - .../client/feign/bpmn/ProcessModelApi.java | 2 - .../client/feign/bpmn/ProcessTaskApi.java | 2 + .../client/feign/bpmn/ProcessVariableApi.java | 2 - .../feign/manage/ProcessCategoryApi.java | 2 +- .../client/feign/manage/ProcessConfigApi.java | 2 +- workflow-engine-spring-boot-starter/pom.xml | 23 ++ .../starter/api/WorkflowCoreService.java | 203 +++++++++++++++++- 26 files changed, 739 insertions(+), 27 deletions(-) create mode 100644 workflow-auto-gen/pom.xml create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java create mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java create mode 100644 workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor delete mode 100644 workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java diff --git a/pom.xml b/pom.xml index 275e50f9c..c64c8e6a1 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,11 @@ workflow-engine-core ${project.version} + + ${project.groupId} + workflow-auto-gen + ${project.version} + ${project.groupId} workflow-engine-server @@ -125,6 +130,11 @@ mapstruct-processor ${mapstruct.version} + + cn.axzo.workflow + workflow-auto-gen + ${revision} + @@ -139,6 +149,7 @@ + workflow-auto-gen workflow-engine-api workflow-engine-common workflow-engine-core diff --git a/workflow-auto-gen/pom.xml b/workflow-auto-gen/pom.xml new file mode 100644 index 000000000..d5c2eaa66 --- /dev/null +++ b/workflow-auto-gen/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + cn.axzo.workflow + workflow-engine + ${revision} + + + workflow-auto-gen + jar + Workflow Auto Gen + + + + com.google.auto.service + auto-service + 1.1.1 + + + com.squareup + javapoet + 1.13.0 + + + + \ No newline at end of file diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java new file mode 100644 index 000000000..114504300 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java @@ -0,0 +1,16 @@ +package cn.axzo.workflow.generate; + +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; + +public abstract class BaseCodeGenProcessor implements CodeGenProcessor { + + public static final String PREFIX = "Base"; + + @Override + public GenCodeInfo generate(TypeElement typeElement, RoundEnvironment roundEnvironment) + throws Exception { + //添加其他逻辑扩展 + return null; + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java new file mode 100644 index 000000000..5b67d4e88 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java @@ -0,0 +1,31 @@ +package cn.axzo.workflow.generate; + +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.lang.annotation.Annotation; + +public interface CodeGenProcessor { + /** + * 需要解析的类上的注解 + * + * @return + */ + Class getAnnotation(); + + /** + * 获取生成的包名 + * + * @param typeElement + * @return + */ + String generatePackage(TypeElement typeElement); + + /** + * 代码生成逻辑. + * + * @param typeElement + * @param roundEnvironment + * @throws Exception + */ + GenCodeInfo generate(TypeElement typeElement, RoundEnvironment roundEnvironment) throws Exception; +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java new file mode 100644 index 000000000..f91adfed1 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java @@ -0,0 +1,43 @@ +package cn.axzo.workflow.generate; + +import com.google.common.collect.Maps; + +import java.lang.annotation.Annotation; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; + +public class CodeGenProcessorRegistry { + private static Map PROCESSORS; + + private CodeGenProcessorRegistry() { + throw new UnsupportedOperationException(); + } + + /** + * 注解处理器要处理的注解集合 + * + * @return + */ + public static Set getSupportedAnnotations() { + return PROCESSORS.keySet(); + } + + public static CodeGenProcessor find(String annotationClassName) { + return PROCESSORS.get(annotationClassName); + } + + /** + * spi 加载所有的processor + * + */ + public static void initProcessors() { + final Map map = Maps.newLinkedHashMap(); + ServiceLoader processors = ServiceLoader.load(CodeGenProcessor.class, CodeGenProcessor.class.getClassLoader()); + for (CodeGenProcessor next : processors) { + Class annotation = next.getAnnotation(); + map.put(annotation.getName(), next); + } + PROCESSORS = map; + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java new file mode 100644 index 000000000..0a758a558 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java @@ -0,0 +1,68 @@ +package cn.axzo.workflow.generate; + +import com.squareup.javapoet.TypeSpec; + +public class GenCodeInfo { + private final TypeSpec typeSpec; + private final String sourcePath; + private final String packageName; + private final String className; + + public static GenCodeInfoBuilder builder() { + return new GenCodeInfoBuilder(); + } + + public TypeSpec getTypeSpec() { + return typeSpec; + } + + public String getSourcePath() { + return sourcePath; + } + + public String getPackageName() { + return packageName; + } + + public String getClassName() { + return className; + } + + private GenCodeInfo(GenCodeInfoBuilder builder) { + this.typeSpec = builder.typeSpec; + this.sourcePath = builder.sourcePath; + this.packageName = builder.packageName; + this.className = builder.className; + } + + public static class GenCodeInfoBuilder { + private TypeSpec typeSpec; + private String sourcePath; + private String packageName; + private String className; + + public GenCodeInfoBuilder typeSpec(TypeSpec typeSpec) { + this.typeSpec = typeSpec; + return this; + } + + public GenCodeInfoBuilder sourcePath(String sourcePath) { + this.sourcePath = sourcePath; + return this; + } + + public GenCodeInfoBuilder packageName(String packageName) { + this.packageName = packageName; + return this; + } + + public GenCodeInfoBuilder className(String className) { + this.className = className; + return this; + } + + public GenCodeInfo build() { + return new GenCodeInfo(this); + } + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java new file mode 100644 index 000000000..6d13d4e8e --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java @@ -0,0 +1,45 @@ +package cn.axzo.workflow.generate; + +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeSpec; + +import javax.lang.model.element.Modifier; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +public class GenJavaSourceFileUtils { + + public static void genJavaSourceFile(String pathStr, String packageName, String className, List methodSpecs) { + TypeSpec typeSpec = TypeSpec + .interfaceBuilder(className) + .addModifiers(Modifier.PUBLIC) + .addMethods(methodSpecs) + .build(); + JavaFile javaFile = JavaFile.builder(packageName, typeSpec) + .addFileComment("--auto generated by workflow auto-gen plugin--") + .build(); + String javaFileName = typeSpec.name + ".java"; + try { + Path path = Paths.get(pathStr); + File packageFolder = new File(path.toFile().getAbsolutePath()); + if (!packageFolder.exists()) { + System.out.println("package not exists:" + path); + return; + } + String javaFilePath = path.toFile().getAbsolutePath() + File.separator + javaFileName; + System.out.println("name:" + javaFilePath); + File sourceFile = new File(javaFilePath); + if (!sourceFile.exists()) { + javaFile.writeTo(packageFolder); + } else { + javaFile.writeTo(packageFolder); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java new file mode 100644 index 000000000..2168b364b --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java @@ -0,0 +1,87 @@ +package cn.axzo.workflow.generate; + +import cn.axzo.workflow.generate.annotition.GenService; +import cn.axzo.workflow.generate.annotition.Management; +import com.google.auto.service.AutoService; +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; + +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; + +@AutoService(CodeGenProcessor.class) +public class GenServiceProcessor extends BaseCodeGenProcessor { + + @Override + public Class getAnnotation() { + return GenService.class; + } + + @Override + public String generatePackage(TypeElement typeElement) { + return typeElement.getAnnotation(GenService.class).genPkgName(); + } + + @Override + public GenCodeInfo generate(TypeElement typeElement, RoundEnvironment roundEnvironment) throws Exception { + String genPkgName = typeElement.getAnnotation(GenService.class).genPkgName(); + String sourcePath = typeElement.getAnnotation(GenService.class).genSourcePath(); + String genClassName = typeElement.getAnnotation(GenService.class).genClassName(); + List enclosedElements = typeElement.getEnclosedElements(); + TypeSpec.Builder targetTypeSpec = TypeSpec.interfaceBuilder(genClassName) + .addModifiers(typeElement.getModifiers().toArray(new Modifier[]{})); + for (Element enclosedElement : enclosedElements) { + if (enclosedElement instanceof ExecutableElement) { + ExecutableElement executableElement = (ExecutableElement) enclosedElement; + List annotationMirrors = executableElement.getAnnotationMirrors(); + boolean add = true; + for (AnnotationMirror annotationMirror : annotationMirrors) { + if (annotationMirror.getAnnotationType().toString().equals(Management.class.getName())) { + add = false; + } + } + if (add) { + List parameterSpecs = new ArrayList<>(); + for (VariableElement variableElement : executableElement.getParameters()) { + parameterSpecs.add(ParameterSpec.get(variableElement)); + } + List annotationSpecs = new ArrayList<>(); + for (AnnotationMirror annotationMirror : annotationMirrors) { + annotationSpecs.add(AnnotationSpec.get(annotationMirror)); + } + List exceptions = new ArrayList<>(); + List thrownTypes = executableElement.getThrownTypes(); + for (TypeMirror typeMirror : thrownTypes) { + exceptions.add(TypeName.get(typeMirror)); + } + MethodSpec main = MethodSpec.methodBuilder(enclosedElement.getSimpleName().toString()) + .addModifiers(enclosedElement.getModifiers()) + .returns(TypeName.get(executableElement.getReturnType())) + .addParameters(parameterSpecs) + .addAnnotations(annotationSpecs) + .addExceptions(exceptions) + .build(); + targetTypeSpec.addMethod(main); + } + } + } + return GenCodeInfo.builder() + .className(genClassName) + .packageName(genPkgName) + .sourcePath(sourcePath) + .typeSpec(targetTypeSpec.build()) + .build(); + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java new file mode 100644 index 000000000..26f2e1d40 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java @@ -0,0 +1,17 @@ +package cn.axzo.workflow.generate; + +import javax.annotation.processing.ProcessingEnvironment; + +public final class ProcessingEnvironmentHolder { + + public static final ThreadLocal environment = new ThreadLocal<>(); + + + public static void setEnvironment(ProcessingEnvironment pe) { + environment.set(pe); + } + + public static ProcessingEnvironment getEnvironment() { + return environment.get(); + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java new file mode 100644 index 000000000..18228e7c7 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java @@ -0,0 +1,128 @@ +package cn.axzo.workflow.generate; + +import com.google.auto.service.AutoService; +import com.squareup.javapoet.MethodSpec; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +@AutoService(Processor.class) +public class WorkflowExposeApiGenProcessor extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + List genCodeInfos = new ArrayList<>(); + annotations.forEach(an -> { + Set typeElements = roundEnv.getElementsAnnotatedWith(an); + Set types = ElementFilter.typesIn(typeElements); + for (TypeElement typeElement : types) { + CodeGenProcessor codeGenProcessor = CodeGenProcessorRegistry.find(an.getQualifiedName().toString()); + try { + GenCodeInfo generate = codeGenProcessor.generate(typeElement, roundEnv); + genCodeInfos.add(generate); + } catch (Exception e) { + ProcessingEnvironmentHolder.getEnvironment().getMessager().printMessage(Diagnostic.Kind.ERROR, "代码生成异常:" + e.getMessage()); + } + } + }); + if (!genCodeInfos.isEmpty()) { + Map, List> apiGenMap = new HashMap<>(); + //进行分组 + for (GenCodeInfo genCodeInfo : genCodeInfos) { + Triplet triplet = Triplet.of(genCodeInfo.getSourcePath(), genCodeInfo.getPackageName(), genCodeInfo.getClassName()); + List codeInfos = apiGenMap.computeIfAbsent(triplet, k -> new ArrayList<>()); + codeInfos.add(genCodeInfo); + } + for (Map.Entry, List> entry : apiGenMap.entrySet()) { + Triplet triplet = entry.getKey(); + List methodSpecs = new ArrayList<>(); + List infos = entry.getValue(); + for (GenCodeInfo genCodeInfo : infos) { + methodSpecs.addAll(genCodeInfo.getTypeSpec().methodSpecs); + } + GenJavaSourceFileUtils.genJavaSourceFile(triplet.getFirst(), triplet.getSecond(), triplet.getThird(), methodSpecs); + } + } + return false; + } + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + ProcessingEnvironmentHolder.setEnvironment(processingEnv); + CodeGenProcessorRegistry.initProcessors(); + } + + @Override + public Set getSupportedAnnotationTypes() { + return CodeGenProcessorRegistry.getSupportedAnnotations(); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + public static final class Triplet { + private final T first; + private final U second; + private final V third; + + public Triplet(T first, U second, V third) { + this.first = first; + this.second = second; + this.third = third; + } + + public T getFirst() { + return first; + } + + public U getSecond() { + return second; + } + + public V getThird() { + return third; + } + + @Override + public String toString() { + return "Triplet{" + + "first=" + first + + ", second=" + second + + ", third=" + third + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Triplet triplet = (Triplet) o; + return Objects.equals(first, triplet.first) && Objects.equals(second, triplet.second) && Objects.equals(third, triplet.third); + } + + @Override + public int hashCode() { + return Objects.hash(first, second, third); + } + + public static Triplet of(T first, U second, V third) { + return new Triplet<>(first, second, third); + } + } +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java new file mode 100644 index 000000000..07a4a7525 --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java @@ -0,0 +1,21 @@ +package cn.axzo.workflow.generate.annotition; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface GenService { + + String genPkgName(); + + String genSourcePath() default "workflow-engine-spring-boot-starter/src/main/java"; + + String genClassName() default "WorkflowCoreService"; + + boolean overrideSource() default false; +} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java new file mode 100644 index 000000000..72de7210f --- /dev/null +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.generate.annotition; + +/** + * 控制接口是否调用受限,标记了注解的方法,表示受控,不允许暴露给客户端使用 + * + * @author wangli + * @since 2024/5/22 10:43 + */ +public @interface Management { +} diff --git a/workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 000000000..ddef324fa --- /dev/null +++ b/workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +cn.axzo.workflow.generate.WorkflowExposeApiGenProcessor \ No newline at end of file diff --git a/workflow-engine-api/pom.xml b/workflow-engine-api/pom.xml index 11ba8fffc..7338f22b9 100644 --- a/workflow-engine-api/pom.xml +++ b/workflow-engine-api/pom.xml @@ -23,6 +23,11 @@ workflow-engine-common ${project.version} + + cn.axzo.workflow + workflow-auto-gen + ${project.version} + io.github.openfeign feign-httpclient diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java deleted file mode 100644 index 570ac2ccc..000000000 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/Management.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.axzo.workflow.client.annotation; - -/** - * 控制接口是否调用受限 - * - * @author wangli - * @since 2024/5/22 10:43 - */ -public @interface Management { -} diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index ee7bb70a8..2ccbf2fd5 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.generate.annotition.Management; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; @@ -24,6 +25,7 @@ public interface ProcessActivityApi { * 业务节点唤醒 */ @GetMapping("/api/process/activity/trigger") + @Management CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, @RequestParam Boolean async); /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java index 34ab705f0..d4e69dfc2 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; @@ -23,7 +22,6 @@ import javax.validation.constraints.NotNull; * @author wangli * @since 2023/9/21 16:25 */ -@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessDefinitionApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index c98b1a8b3..cac26bc3d 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -15,6 +15,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAd import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.generate.annotition.GenService; import cn.azxo.framework.common.model.CommonResponse; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; @@ -40,6 +41,7 @@ import java.util.Map; * @since 2023/9/21 16:26 */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") +@GenService(genPkgName = "cn.axzo.workflow.starter.api") public interface ProcessInstanceApi { /** * 查询所有的审批流 diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index 6e0143766..b30e0b1e0 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -1,12 +1,10 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.annotation.Management; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; -@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessJobApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index 97092ea47..29d7f5878 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; @@ -28,7 +27,6 @@ import java.util.List; * @author wangli * @since 2023/9/21 15:47 */ -@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessModelApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 7a53d6fac..e7491986c 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -16,6 +16,7 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstance import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import cn.axzo.workflow.generate.annotition.GenService; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; @@ -39,6 +40,7 @@ import java.util.Map; * @since 2023/9/21 16:26 */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") +@GenService(genPkgName = "cn.axzo.workflow.starter.api") public interface ProcessTaskApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java index 3bbe433b2..04266a7f4 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.annotation.Management; import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -16,7 +15,6 @@ import javax.validation.constraints.NotBlank; /** * 流程变量api */ -@Management @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessVariableApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index a62b2b6df..436f02a23 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.client.feign.manage; -import cn.axzo.workflow.client.annotation.Management; +import cn.axzo.workflow.generate.annotition.Management; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java index 5611a33df..a5c3bbea9 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.client.feign.manage; -import cn.axzo.workflow.client.annotation.Management; +import cn.axzo.workflow.generate.annotition.Management; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index 20935efe3..38fa2f018 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -19,10 +19,33 @@ cn.axzo.workflow workflow-engine-api + + cn.axzo.workflow + workflow-auto-gen + cn.axzo.framework.rocketmq axzo-common-rocketmq provided + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + + cn.axzo.workflow + workflow-auto-gen + ${revision} + + + + + + diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 93f09fe3a..5ef1dc18f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,14 +1,203 @@ +// --auto generated by workflow auto-gen plugin-- package cn.axzo.workflow.starter.api; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import cn.azxo.framework.common.model.CommonResponse; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.v3.oas.annotations.Operation; +import java.lang.Boolean; +import java.lang.Integer; +import java.lang.Object; +import java.lang.String; +import java.lang.Void; +import java.util.List; +import java.util.Map; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; -/** - * 模拟生成的受限访问的接口定义 - * - * @author wangli - * @since 2024/5/28 16:12 - */ public interface WorkflowCoreService { + @GetMapping("/api/process/task/page/todo") + CommonResponse> getTodoTaskPage(BpmnTaskPageSearchDTO dto); - String createProcessInstance(BpmnProcessInstanceCreateDTO dto); + @GetMapping("/api/process/task/page/done") + CommonResponse> getDoneTaskPage(BpmnTaskPageSearchDTO dto); + + @GetMapping("/api/process/task/list/flat") + CommonResponse> getTaskListFlatByProcessInstanceId( + String processInstanceId, String tenantId); + + @GetMapping("/api/process/task/list/group") + CommonResponse> getTaskListGroupByProcessInstanceId( + String processInstanceId, String tenantId); + + @GetMapping("/api/process/task/active/list") + CommonResponse> getActiveTasksByProcessInstanceId( + String processInstanceId, String tenantId); + + @PostMapping("/api/process/task/approve") + CommonResponse approveTask(BpmnTaskAuditDTO dto); + + @PostMapping("/api/process/task/batch/approve") + CommonResponse batchApproveTask(List dtos); + + @PostMapping("/api/process/task/reject") + CommonResponse rejectTask(BpmnTaskAuditDTO dto); + + @PostMapping("/api/process/task/batch/reject") + CommonResponse batchRejectTask(List dtos); + + @Operation( + summary = "直接修改审批任务的审批人" + ) + @PostMapping("/api/process/task/transfer") + CommonResponse transferTask(BpmnTaskTransferDTO dto); + + @Operation( + summary = "批量修改审批任务的审批人" + ) + @PostMapping("/api/process/task/batch/transfer") + CommonResponse batchTransferTask(List dtos); + + @Operation( + summary = "审批流程评论" + ) + @PostMapping("/api/process/task/comment") + CommonResponse commentTask(BpmnTaskCommentDTO dto); + + @Operation( + summary = "添加附件" + ) + @PostMapping("/api/process/task/attachment") + CommonResponse addAttachment(BpmnTaskAttachmentDTO dto); + + @Operation( + summary = "审批流程加签" + ) + @PostMapping("/api/process/task/countersign") + CommonResponse countersignTask(BpmnTaskCountersignDTO dto); + + @Operation( + summary = "审批流程催办" + ) + @PostMapping("/api/process/task/remind") + CommonResponse remindTask(BpmnTaskRemindDTO dto); + + @Operation( + summary = "创建机器人节点, 暂停流程任务" + ) + @PostMapping("/api/process/task/robot/create") + CommonResponse createRobotTask(BpmnRobotTaskCreateDTO dto); + + @Operation( + summary = "完成机器人节点, 继续流程任务" + ) + @PostMapping("/api/process/task/robot/complete") + CommonResponse completeRobotTask(BpmnRobotTaskCompleteDTO dto); + + @Operation( + summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" + ) + @GetMapping("/api/process/task/find") + CommonResponse findTaskIdByInstanceIdAndPersonId(String processInstanceId, + String personId); + + @Operation( + summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" + ) + @GetMapping("/api/process/task/batch/find") + CommonResponse> findTaskIdByInstanceIdsAndPersonId( + List processInstanceIds, String personId); + + @PostMapping("/api/process/instance/page/all") + CommonResponse> getAllProcessInstancePage( + BpmnProcessInstanceAdminPageReqVO dto); + + @PostMapping("/api/process/instance/page/my") + CommonResponse> getMyProcessInstancePage( + BpmnProcessInstanceMyPageReqVO dto); + + @PostMapping("/api/process/instance/create") + CommonResponse createProcessInstance(BpmnProcessInstanceCreateDTO dto); + + @PostMapping("/api/process/instance/form/create") + CommonResponse createProcessInstanceWith(BpmnProcessInstanceCreateWithFormDTO dto); + + @DeleteMapping("/api/process/instance/cancel") + CommonResponse cancelProcessInstance(BpmnProcessInstanceCancelDTO dto); + + @DeleteMapping("/api/process/instance/abort") + CommonResponse abortProcessInstance(BpmnProcessInstanceAbortDTO dto); + + @DeleteMapping("/api/process/instance/batch/abort") + CommonResponse batchAbortProcessInstance( + List dtos); + + @PostMapping("/api/process/instance/carbon-copy") + CommonResponse carbonCopyProcessInstance(BpmnProcessInstanceCarbonCopyDTO dto); + + @GetMapping("/api/process/instance/get") + CommonResponse getProcessInstanceVO(BpmnProcessInstanceQueryDTO dto); + + @Operation( + summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" + ) + @PutMapping("/api/process/instance/status/update") + CommonResponse updateProcessStatus(String processDefinitionId, Integer status); + + @GetMapping("/api/process/instance/graphical") + CommonResponse processInstanceGraphical(String processInstanceId, String tenantId); + + @GetMapping("/api/process/instance/node/forecasting") + CommonResponse> processInstanceNodeForecast(String processInstanceId, + String tenantId); + + @GetMapping("/api/process/instance/node/filter/forecasting") + CommonResponse> processInstanceFilterNodeForecast( + String processInstanceId, String tenantId, Boolean allNode, List nodeDefinitionKeys); + + @GetMapping("/api/process/instance/cooperation-org") + CommonResponse> getProcessVariables(String processInstanceId, + String tenantId); + + @Operation( + summary = "查询实例的租户集合" + ) + @GetMapping("/api/process/instance/tenant/ids") + CommonResponse> getTenantIds(); + + @Operation( + summary = "校验指定流程实例下,是否存在指定的审批人" + ) + @PostMapping("/api/process/instance/check/approver") + CommonResponse checkInstanceApprover(BpmnProcessInstanceCheckApproverDTO dto); } From c15419f345ab5e4e76153aca39ee806f8cda2fb5 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 29 May 2024 15:18:25 +0800 Subject: [PATCH 015/210] =?UTF-8?q?update=20-=20REQ-2516-=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=BC=96=E8=AF=91=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pom.xml b/pom.xml index c64c8e6a1..78331280a 100644 --- a/pom.xml +++ b/pom.xml @@ -130,11 +130,6 @@ mapstruct-processor ${mapstruct.version} - - cn.axzo.workflow - workflow-auto-gen - ${revision} - From 25f2a1256b19da9abb445f6725e554b5964221f4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 May 2024 16:26:16 +0800 Subject: [PATCH 016/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=87=8D?= =?UTF-8?q?=E7=BD=AEWorkflowCoreService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 206 ++---------------- 1 file changed, 13 insertions(+), 193 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 5ef1dc18f..4c24c5d48 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,203 +1,23 @@ -// --auto generated by workflow auto-gen plugin-- package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterConfiguration; import cn.azxo.framework.common.model.CommonResponse; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.swagger.v3.oas.annotations.Operation; -import java.lang.Boolean; -import java.lang.Integer; -import java.lang.Object; -import java.lang.String; -import java.lang.Void; -import java.util.List; -import java.util.Map; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +/** + * 模拟生成的受限访问的接口定义 + * + * @author wangli + * @since 2024/5/28 16:12 + */ +@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterConfiguration.class) public interface WorkflowCoreService { - @GetMapping("/api/process/task/page/todo") - CommonResponse> getTodoTaskPage(BpmnTaskPageSearchDTO dto); - - @GetMapping("/api/process/task/page/done") - CommonResponse> getDoneTaskPage(BpmnTaskPageSearchDTO dto); - - @GetMapping("/api/process/task/list/flat") - CommonResponse> getTaskListFlatByProcessInstanceId( - String processInstanceId, String tenantId); - - @GetMapping("/api/process/task/list/group") - CommonResponse> getTaskListGroupByProcessInstanceId( - String processInstanceId, String tenantId); - - @GetMapping("/api/process/task/active/list") - CommonResponse> getActiveTasksByProcessInstanceId( - String processInstanceId, String tenantId); - - @PostMapping("/api/process/task/approve") - CommonResponse approveTask(BpmnTaskAuditDTO dto); - - @PostMapping("/api/process/task/batch/approve") - CommonResponse batchApproveTask(List dtos); - - @PostMapping("/api/process/task/reject") - CommonResponse rejectTask(BpmnTaskAuditDTO dto); - - @PostMapping("/api/process/task/batch/reject") - CommonResponse batchRejectTask(List dtos); - - @Operation( - summary = "直接修改审批任务的审批人" - ) - @PostMapping("/api/process/task/transfer") - CommonResponse transferTask(BpmnTaskTransferDTO dto); - - @Operation( - summary = "批量修改审批任务的审批人" - ) - @PostMapping("/api/process/task/batch/transfer") - CommonResponse batchTransferTask(List dtos); - - @Operation( - summary = "审批流程评论" - ) - @PostMapping("/api/process/task/comment") - CommonResponse commentTask(BpmnTaskCommentDTO dto); - - @Operation( - summary = "添加附件" - ) - @PostMapping("/api/process/task/attachment") - CommonResponse addAttachment(BpmnTaskAttachmentDTO dto); - - @Operation( - summary = "审批流程加签" - ) - @PostMapping("/api/process/task/countersign") - CommonResponse countersignTask(BpmnTaskCountersignDTO dto); - - @Operation( - summary = "审批流程催办" - ) - @PostMapping("/api/process/task/remind") - CommonResponse remindTask(BpmnTaskRemindDTO dto); - - @Operation( - summary = "创建机器人节点, 暂停流程任务" - ) - @PostMapping("/api/process/task/robot/create") - CommonResponse createRobotTask(BpmnRobotTaskCreateDTO dto); - - @Operation( - summary = "完成机器人节点, 继续流程任务" - ) - @PostMapping("/api/process/task/robot/complete") - CommonResponse completeRobotTask(BpmnRobotTaskCompleteDTO dto); - - @Operation( - summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" - ) - @GetMapping("/api/process/task/find") - CommonResponse findTaskIdByInstanceIdAndPersonId(String processInstanceId, - String personId); - - @Operation( - summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" - ) - @GetMapping("/api/process/task/batch/find") - CommonResponse> findTaskIdByInstanceIdsAndPersonId( - List processInstanceIds, String personId); - - @PostMapping("/api/process/instance/page/all") - CommonResponse> getAllProcessInstancePage( - BpmnProcessInstanceAdminPageReqVO dto); - - @PostMapping("/api/process/instance/page/my") - CommonResponse> getMyProcessInstancePage( - BpmnProcessInstanceMyPageReqVO dto); @PostMapping("/api/process/instance/create") - CommonResponse createProcessInstance(BpmnProcessInstanceCreateDTO dto); - - @PostMapping("/api/process/instance/form/create") - CommonResponse createProcessInstanceWith(BpmnProcessInstanceCreateWithFormDTO dto); - - @DeleteMapping("/api/process/instance/cancel") - CommonResponse cancelProcessInstance(BpmnProcessInstanceCancelDTO dto); - - @DeleteMapping("/api/process/instance/abort") - CommonResponse abortProcessInstance(BpmnProcessInstanceAbortDTO dto); - - @DeleteMapping("/api/process/instance/batch/abort") - CommonResponse batchAbortProcessInstance( - List dtos); - - @PostMapping("/api/process/instance/carbon-copy") - CommonResponse carbonCopyProcessInstance(BpmnProcessInstanceCarbonCopyDTO dto); - - @GetMapping("/api/process/instance/get") - CommonResponse getProcessInstanceVO(BpmnProcessInstanceQueryDTO dto); - - @Operation( - summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" - ) - @PutMapping("/api/process/instance/status/update") - CommonResponse updateProcessStatus(String processDefinitionId, Integer status); - - @GetMapping("/api/process/instance/graphical") - CommonResponse processInstanceGraphical(String processInstanceId, String tenantId); - - @GetMapping("/api/process/instance/node/forecasting") - CommonResponse> processInstanceNodeForecast(String processInstanceId, - String tenantId); - - @GetMapping("/api/process/instance/node/filter/forecasting") - CommonResponse> processInstanceFilterNodeForecast( - String processInstanceId, String tenantId, Boolean allNode, List nodeDefinitionKeys); - - @GetMapping("/api/process/instance/cooperation-org") - CommonResponse> getProcessVariables(String processInstanceId, - String tenantId); - - @Operation( - summary = "查询实例的租户集合" - ) - @GetMapping("/api/process/instance/tenant/ids") - CommonResponse> getTenantIds(); - - @Operation( - summary = "校验指定流程实例下,是否存在指定的审批人" - ) - @PostMapping("/api/process/instance/check/approver") - CommonResponse checkInstanceApprover(BpmnProcessInstanceCheckApproverDTO dto); + CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); } + From 66e2b475c9fba2cdd6e80922bc48f1e7e872ca63 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 29 May 2024 19:25:19 +0800 Subject: [PATCH 017/210] =?UTF-8?q?update=20-=20REQ-2516-=E6=B5=81?= =?UTF-8?q?=E7=A8=8Bfeign=E7=9A=84api=E6=B7=BB=E5=8A=A0swagger=E7=9A=84@Op?= =?UTF-8?q?eration=E6=B3=A8=E8=A7=A3=EF=BC=8C=E6=96=B9=E4=BE=BF=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E6=96=B9=E4=BA=86=E8=A7=A3=E6=8E=A5=E5=8F=A3=E7=94=A8?= =?UTF-8?q?=E9=80=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessActivityApi.java | 4 +++- .../client/feign/bpmn/ProcessInstanceApi.java | 14 ++++++++++++++ .../workflow/client/feign/bpmn/ProcessTaskApi.java | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 2ccbf2fd5..3ebcdb265 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.axzo.workflow.generate.annotition.Management; import cn.azxo.framework.common.model.CommonResponse; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -24,8 +25,8 @@ public interface ProcessActivityApi { /** * 业务节点唤醒 */ + @Operation(summary = "业务节点唤醒") @GetMapping("/api/process/activity/trigger") - @Management CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, @RequestParam Boolean async); /** @@ -35,5 +36,6 @@ public interface ProcessActivityApi { * @return */ @PostMapping("/api/process/activity/assignee/set") + @Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人") CommonResponse setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index cac26bc3d..006bd9277 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -19,6 +19,7 @@ import cn.axzo.workflow.generate.annotition.GenService; import cn.azxo.framework.common.model.CommonResponse; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; @@ -48,12 +49,14 @@ public interface ProcessInstanceApi { * * @return */ + @Operation(summary = "查询所有的审批流") @PostMapping("/api/process/instance/page/all") CommonResponse> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); /** * 我发起的审批列表 */ + @Operation(summary = "我发起的审批列表") @PostMapping("/api/process/instance/page/my") CommonResponse> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); @@ -68,6 +71,7 @@ public interface ProcessInstanceApi { * * @param dto {@link BpmnProcessInstanceCreateDTO} */ + @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") @PostMapping("/api/process/instance/create") CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); @@ -77,6 +81,7 @@ public interface ProcessInstanceApi { * @param dto * @return */ + @Operation(summary = "创建审批流程并带上表单") @PostMapping("/api/process/instance/form/create") CommonResponse createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); @@ -92,6 +97,7 @@ public interface ProcessInstanceApi { * @param dto {@link BpmnProcessInstanceCancelDTO} * @return */ + @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件") @DeleteMapping("/api/process/instance/cancel") CommonResponse cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto); @@ -101,6 +107,7 @@ public interface ProcessInstanceApi { * @param dto * @return */ + @Operation(summary = "中止流程实例") @DeleteMapping("/api/process/instance/abort") CommonResponse abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto); @@ -110,6 +117,7 @@ public interface ProcessInstanceApi { * @param dtos * @return */ + @Operation(summary = "批量中止流程实例") @DeleteMapping("/api/process/instance/batch/abort") CommonResponse batchAbortProcessInstance(@Validated @RequestBody List dtos); @@ -119,6 +127,7 @@ public interface ProcessInstanceApi { * @param dto * @return */ + @Operation(summary = "抄送流程实例") @PostMapping("/api/process/instance/carbon-copy") CommonResponse carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); @@ -128,6 +137,7 @@ public interface ProcessInstanceApi { * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询 * @return 流程实例, 租户Id不必传 */ + @Operation(summary = "获得流程实例") @GetMapping("/api/process/instance/get") CommonResponse getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); @@ -149,6 +159,7 @@ public interface ProcessInstanceApi { * @param tenantId * @return */ + @Operation(summary = "获取审批流程实例的运行图") @GetMapping("/api/process/instance/graphical") CommonResponse processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -158,6 +169,7 @@ public interface ProcessInstanceApi { * * @return */ + @Operation(summary = "推断指定流程实例的所有节点执行顺序") @GetMapping("/api/process/instance/node/forecasting") CommonResponse> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -169,6 +181,7 @@ public interface ProcessInstanceApi { * 如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点 * @return */ + @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") @GetMapping("/api/process/instance/node/filter/forecasting") CommonResponse> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @@ -182,6 +195,7 @@ public interface ProcessInstanceApi { * @param tenantId * @return */ + @Operation(summary = "获取指定流程实例的流程变量") @GetMapping("/api/process/instance/cooperation-org") CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index e7491986c..f34fbb641 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -46,12 +46,14 @@ public interface ProcessTaskApi { /** * 待审核列表 */ + @Operation(summary = "待审核列表") @GetMapping("/api/process/task/page/todo") CommonResponse> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** * 已完成的审批列表 */ + @Operation(summary = "已完成的审批列表") @GetMapping("/api/process/task/page/done") CommonResponse> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); @@ -60,6 +62,7 @@ public interface ProcessTaskApi { *

* 同一层级结构 */ + @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/flat") CommonResponse> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -69,6 +72,7 @@ public interface ProcessTaskApi { *

* 分组结构 */ + @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/group") CommonResponse> getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -76,6 +80,7 @@ public interface ProcessTaskApi { /** * 获取实例正在审核的人列表 */ + @Operation(summary = "获取实例正在审核的人列表") @GetMapping("/api/process/task/active/list") CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); @@ -90,6 +95,7 @@ public interface ProcessTaskApi { * 2.2. 流程实例正常结束会触发 process-instance-completed 事件 * */ + @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") @PostMapping("/api/process/task/approve") CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); @@ -99,6 +105,7 @@ public interface ProcessTaskApi { * @param dtos * @return */ + @Operation(summary = "批量同意") @PostMapping("/api/process/task/batch/approve") CommonResponse batchApproveTask(@Validated @RequestBody List dtos); @@ -111,6 +118,7 @@ public interface ProcessTaskApi { * 2. 当前流程实例会触发 process-instance-rejected 事件 * */ + @Operation(summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件") @PostMapping("/api/process/task/reject") CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); From d4e784901c1a930b604af440fc1b4ae353877e16 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 29 May 2024 19:27:58 +0800 Subject: [PATCH 018/210] =?UTF-8?q?update=20-=20REQ-2516-=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=94=9F=E6=88=90=E6=8E=A5=E5=8F=A3=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E4=B8=A2=E5=A4=B1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/generate/GenServiceProcessor.java | 11 ++++++++++- .../axzo/workflow/generate/annotition/GenService.java | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java index 2168b364b..2d4a90603 100644 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java @@ -55,7 +55,16 @@ public class GenServiceProcessor extends BaseCodeGenProcessor { if (add) { List parameterSpecs = new ArrayList<>(); for (VariableElement variableElement : executableElement.getParameters()) { - parameterSpecs.add(ParameterSpec.get(variableElement)); + ParameterSpec parameterSpec = ParameterSpec.get(variableElement); + List paramAnnotations = variableElement.getAnnotationMirrors(); + if (paramAnnotations != null && !paramAnnotations.isEmpty()) { + List annotationSpecs = new ArrayList<>(); + for (AnnotationMirror annotation : paramAnnotations) { + annotationSpecs.add(AnnotationSpec.get(annotation)); + } + parameterSpec = parameterSpec.toBuilder().addAnnotations(annotationSpecs).build(); + } + parameterSpecs.add(parameterSpec); } List annotationSpecs = new ArrayList<>(); for (AnnotationMirror annotationMirror : annotationMirrors) { diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java index 07a4a7525..2b7e414ac 100644 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java +++ b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java @@ -15,7 +15,7 @@ public @interface GenService { String genSourcePath() default "workflow-engine-spring-boot-starter/src/main/java"; - String genClassName() default "WorkflowCoreService"; + String genClassName() default "WorkflowCoreService_Gen"; boolean overrideSource() default false; } From fafec688b5701a714f5a0d815597277964aaca43 Mon Sep 17 00:00:00 2001 From: wangli Date: Wed, 29 May 2024 22:34:03 +0800 Subject: [PATCH 019/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=BC=96=E8=AF=91=E6=97=B6=E7=94=9F=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 +- .../starter/api/WorkflowCoreService_Gen.java | 294 ++++++++++++++++++ 2 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java diff --git a/pom.xml b/pom.xml index 78331280a..a9f1a2ab8 100644 --- a/pom.xml +++ b/pom.xml @@ -130,6 +130,11 @@ mapstruct-processor ${mapstruct.version} + + cn.axzo.workflow + workflow-auto-gen + ${revision} + @@ -144,7 +149,6 @@ - workflow-auto-gen workflow-engine-api workflow-engine-common workflow-engine-core diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java new file mode 100644 index 000000000..5c566a6c7 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java @@ -0,0 +1,294 @@ +// --auto generated by workflow auto-gen plugin-- +package cn.axzo.workflow.starter.api; + +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import cn.azxo.framework.common.model.CommonResponse; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +public interface WorkflowCoreService_Gen { + @Operation( + summary = "待审核列表" + ) + @GetMapping("/api/process/task/page/todo") + CommonResponse> getTodoTaskPage( + @Validated @RequestBody BpmnTaskPageSearchDTO dto); + + @Operation( + summary = "已完成的审批列表" + ) + @GetMapping("/api/process/task/page/done") + CommonResponse> getDoneTaskPage( + @Validated @RequestBody BpmnTaskPageSearchDTO dto); + + @Operation( + summary = "获取指定流程实例的审批过程信息" + ) + @GetMapping("/api/process/task/list/flat") + CommonResponse> getTaskListFlatByProcessInstanceId( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + @Operation( + summary = "获取指定流程实例的审批过程信息" + ) + @GetMapping("/api/process/task/list/group") + CommonResponse> getTaskListGroupByProcessInstanceId( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + @Operation( + summary = "获取实例正在审核的人列表" + ) + @GetMapping("/api/process/task/active/list") + CommonResponse> getActiveTasksByProcessInstanceId( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + + @Operation( + summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件" + ) + @PostMapping("/api/process/task/approve") + CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + @Operation( + summary = "批量同意" + ) + @PostMapping("/api/process/task/batch/approve") + CommonResponse batchApproveTask( + @Validated @RequestBody List dtos); + + @Operation( + summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件" + ) + @PostMapping("/api/process/task/reject") + CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + @PostMapping("/api/process/task/batch/reject") + CommonResponse batchRejectTask( + @Validated @RequestBody List dtos); + + @Operation( + summary = "直接修改审批任务的审批人" + ) + @PostMapping("/api/process/task/transfer") + CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); + + @Operation( + summary = "批量修改审批任务的审批人" + ) + @PostMapping("/api/process/task/batch/transfer") + CommonResponse batchTransferTask( + @Validated @RequestBody List dtos); + + @Operation( + summary = "审批流程评论" + ) + @PostMapping("/api/process/task/comment") + CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); + + @Operation( + summary = "添加附件" + ) + @PostMapping("/api/process/task/attachment") + CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); + + @Operation( + summary = "审批流程加签" + ) + @PostMapping("/api/process/task/countersign") + CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); + + @Operation( + summary = "审批流程催办" + ) + @PostMapping("/api/process/task/remind") + CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); + + @Operation( + summary = "创建机器人节点, 暂停流程任务" + ) + @PostMapping("/api/process/task/robot/create") + CommonResponse createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); + + @Operation( + summary = "完成机器人节点, 继续流程任务" + ) + @PostMapping("/api/process/task/robot/complete") + CommonResponse completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); + + @Operation( + summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" + ) + @GetMapping("/api/process/task/find") + CommonResponse findTaskIdByInstanceIdAndPersonId( + @RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, + @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + + @Operation( + summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" + ) + @GetMapping("/api/process/task/batch/find") + CommonResponse> findTaskIdByInstanceIdsAndPersonId( + @RequestParam(required = false) @NotNull(message = "流程实例 ID列表 不能为空") List processInstanceIds, + @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + + @Operation( + summary = "查询所有的审批流" + ) + @PostMapping("/api/process/instance/page/all") + CommonResponse> getAllProcessInstancePage( + @Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); + + @Operation( + summary = "我发起的审批列表" + ) + @PostMapping("/api/process/instance/page/my") + CommonResponse> getMyProcessInstancePage( + @Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); + + @Operation( + summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件" + ) + @PostMapping("/api/process/instance/create") + CommonResponse createProcessInstance( + @Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + + @Operation( + summary = "创建审批流程并带上表单" + ) + @PostMapping("/api/process/instance/form/create") + CommonResponse createProcessInstanceWith( + @Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); + + @Operation( + summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件" + ) + @DeleteMapping("/api/process/instance/cancel") + CommonResponse cancelProcessInstance( + @Validated @RequestBody BpmnProcessInstanceCancelDTO dto); + + @Operation( + summary = "中止流程实例" + ) + @DeleteMapping("/api/process/instance/abort") + CommonResponse abortProcessInstance( + @Validated @RequestBody BpmnProcessInstanceAbortDTO dto); + + @Operation( + summary = "批量中止流程实例" + ) + @DeleteMapping("/api/process/instance/batch/abort") + CommonResponse batchAbortProcessInstance( + @Validated @RequestBody List dtos); + + @Operation( + summary = "抄送流程实例" + ) + @PostMapping("/api/process/instance/carbon-copy") + CommonResponse carbonCopyProcessInstance( + @Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); + + @Operation( + summary = "获得流程实例" + ) + @GetMapping("/api/process/instance/get") + CommonResponse getProcessInstanceVO( + @Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + + @Operation( + summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" + ) + @PutMapping("/api/process/instance/status/update") + CommonResponse updateProcessStatus( + @NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, + @NotNull(message = "状态不能为空") @RequestParam Integer status); + + @Operation( + summary = "获取审批流程实例的运行图" + ) + @GetMapping("/api/process/instance/graphical") + CommonResponse processInstanceGraphical( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + @Operation( + summary = "推断指定流程实例的所有节点执行顺序" + ) + @GetMapping("/api/process/instance/node/forecasting") + CommonResponse> processInstanceNodeForecast( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + @Operation( + summary = "推断指定流程实例的过滤掉部分节点执行顺序" + ) + @GetMapping("/api/process/instance/node/filter/forecasting") + CommonResponse> processInstanceFilterNodeForecast( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId, + @RequestParam(required = false, defaultValue = "false") Boolean allNode, + @Nullable @RequestParam(required = false) List nodeDefinitionKeys); + + @Operation( + summary = "获取指定流程实例的流程变量" + ) + @GetMapping("/api/process/instance/cooperation-org") + CommonResponse> getProcessVariables( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + @Operation( + summary = "查询实例的租户集合" + ) + @GetMapping("/api/process/instance/tenant/ids") + CommonResponse> getTenantIds(); + + @Operation( + summary = "校验指定流程实例下,是否存在指定的审批人" + ) + @PostMapping("/api/process/instance/check/approver") + CommonResponse checkInstanceApprover( + @Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); +} From 1ff83bf6796c5cc07c13ceca9130c4190f4db318 Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 30 May 2024 00:26:33 +0800 Subject: [PATCH 020/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=8E=A5=E5=8F=A3=E7=9A=84=E5=90=8C=E6=AD=A5=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 2 +- .../starter/api/WorkflowCoreService.java | 24 +++++-- .../starter/common/util/ThreadUtil.java | 22 +++++++ .../feign/ext/ComplexInvokeClient.java | 24 +++++-- .../WorkflowEngineStarterConfiguration.java | 8 +++ ...orkflowEngineStarterInvocationHandler.java | 65 +++++++++++++++++++ ...EngineStarterInvocationHandlerFactory.java | 21 ++++++ 7 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 4f8b71434..a6cc9eafc 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -137,7 +137,7 @@ public class TestController { dto.setCooperationOrg(new CooperationOrgDTO()); dto.setBusinessKey("businessKey"); dto.setInitiator(new BpmnTaskDelegateAssigner()); - workflowCoreService.createProcessInstance(dto); + workflowCoreService.async().createProcessInstance(dto); return CommonResponse.success(true); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 4c24c5d48..9e5b62e63 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; +import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterConfiguration; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -14,10 +16,24 @@ import org.springframework.web.bind.annotation.RequestBody; * @author wangli * @since 2024/5/28 16:12 */ -@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterConfiguration.class) +@FeignClient(name = "workflow-engine-starter", + url = "${axzo.service.workflow-engine:workflow-engine:8080}", + configuration = WorkflowEngineStarterConfiguration.class) public interface WorkflowCoreService { - @PostMapping("/api/process/instance/create") - CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); -} + @PostMapping("/api/process/instance/create") + CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + default WorkflowCoreService sync() { + ThreadUtil.set(RpcInvokeModeEnum.SYNC); + return this; + } + + ; + + default WorkflowCoreService async() { + ThreadUtil.set(RpcInvokeModeEnum.ASYNC); + return this; + } + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java new file mode 100644 index 000000000..bccb06b78 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java @@ -0,0 +1,22 @@ +package cn.axzo.workflow.starter.common.util; + +import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; + +/** + * TODO + * + * @author wangli + * @since 2024/5/29 23:57 + */ +public class ThreadUtil { + + final static InheritableThreadLocal threadLocal = new InheritableThreadLocal<>(); + + public static void set(RpcInvokeModeEnum rpcInvokeMode) { + threadLocal.set(rpcInvokeMode); + } + + public static RpcInvokeModeEnum get() { + return threadLocal.get(); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 2b03d99b4..26238a071 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -3,11 +3,13 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; +import cn.axzo.workflow.starter.common.util.ThreadUtil; import feign.Client; import feign.Request; import feign.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; import java.io.IOException; import java.util.Collection; @@ -40,18 +42,30 @@ public class ComplexInvokeClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { log.info("ComplexInvokeClient execute"); - RpcInvokeModeEnum invokeMode = getInvokeMode(request); - if (Objects.equals(SYNC, invokeMode)) { + RpcInvokeModeEnum currentInvokeModeEnum = ThreadUtil.get(); + + if (Objects.isNull(currentInvokeModeEnum)) { + currentInvokeModeEnum = getDefaultInvokeMode(request); + ; + } + + if (Objects.equals(SYNC, currentInvokeModeEnum)) { return feignClient.execute(request, options); } - Map> headers = request.headers(); headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); - return null; + + // TODO 发送 RPC 调用动作的 MQ 事件 + + return Response.builder() + .status(HttpStatus.OK.value()) + .body(new byte[0]) + .request(request) + .build(); } - private RpcInvokeModeEnum getInvokeMode(Request request) { + private RpcInvokeModeEnum getDefaultInvokeMode(Request request) { Collection invokeModel = request.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.singletonList(starterProperties.getInvokeMode().name())); if (invokeModel == null || invokeModel.isEmpty()) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java index 83778f979..a8bbe4d88 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import feign.Client; import feign.RequestInterceptor; +import org.springframework.cloud.openfeign.FeignBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; @@ -29,4 +30,11 @@ public class WorkflowEngineStarterConfiguration { template.header(STARTER_INVOKE_MODE, starterProperties.getInvokeMode().name()); }; } + + @Bean + public FeignBuilderCustomizer workflowEngineFeignBuilderCustomizer() { + return builder -> { + builder.invocationHandlerFactory(new WorkflowEngineStarterInvocationHandlerFactory()); + }; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java new file mode 100644 index 000000000..ef8ce52ba --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -0,0 +1,65 @@ +package cn.axzo.workflow.starter.feign.ext; + +import feign.InvocationHandlerFactory; +import feign.Target; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; + +/** + * TODO + * + * @author wangli + * @since 2024/5/29 22:58 + */ +public class WorkflowEngineStarterInvocationHandler implements InvocationHandler { + + private final Target target; + private final Map dispatch; + + public WorkflowEngineStarterInvocationHandler(Target target, Map dispatch) { + this.target = target; + this.dispatch = dispatch; + } + + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("equals".equals(method.getName())) { + try { + Object otherHandler = + args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; + return equals(otherHandler); + } catch (IllegalArgumentException e) { + return false; + } + } else if ("hashCode".equals(method.getName())) { + return hashCode(); + } else if ("toString".equals(method.getName())) { + return toString(); + } + + return dispatch.get(method).invoke(args); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof WorkflowEngineStarterInvocationHandler) { + WorkflowEngineStarterInvocationHandler other = (WorkflowEngineStarterInvocationHandler) obj; + return target.equals(other.target); + } + return false; + } + + @Override + public int hashCode() { + return target.hashCode(); + } + + @Override + public String toString() { + return target.toString(); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java new file mode 100644 index 000000000..028e6d66f --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java @@ -0,0 +1,21 @@ +package cn.axzo.workflow.starter.feign.ext; + +import feign.InvocationHandlerFactory; +import feign.Target; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * TODO + * + * @author wangli + * @since 2024/5/29 22:56 + */ +public class WorkflowEngineStarterInvocationHandlerFactory implements InvocationHandlerFactory { + @Override + public InvocationHandler create(Target target, Map dispatch) { + return new WorkflowEngineStarterInvocationHandler(target, dispatch); + } +} From a9937c722cb77e0422302920a75b2b36cc52141f Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 30 May 2024 00:31:25 +0800 Subject: [PATCH 021/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=8E=A5=E5=8F=A3=E7=9A=84=E5=90=8C=E6=AD=A5=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/api/WorkflowCoreService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 9e5b62e63..2255fb285 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,7 +1,6 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterConfiguration; import cn.azxo.framework.common.model.CommonResponse; @@ -10,6 +9,9 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; + /** * 模拟生成的受限访问的接口定义 * @@ -25,14 +27,12 @@ public interface WorkflowCoreService { CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); default WorkflowCoreService sync() { - ThreadUtil.set(RpcInvokeModeEnum.SYNC); + ThreadUtil.set(SYNC); return this; } - ; - default WorkflowCoreService async() { - ThreadUtil.set(RpcInvokeModeEnum.ASYNC); + ThreadUtil.set(ASYNC); return this; } From 09cdfc195aba5bdd1fcc725244057c80c6381da9 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 30 May 2024 11:07:53 +0800 Subject: [PATCH 022/210] =?UTF-8?q?update=20-=20REQ-2516-starter=E7=9A=84p?= =?UTF-8?q?om=E6=96=87=E4=BB=B6=E5=8E=BB=E6=8E=89=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index 38fa2f018..28a852e99 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -29,23 +29,4 @@ provided - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.10.1 - - - - cn.axzo.workflow - workflow-auto-gen - ${revision} - - - - - - From 7bcacc1e1993626c0a3b4a0633fc969e5bf43fa8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:45:37 +0800 Subject: [PATCH 023/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=20Starter=20=E4=B8=AD=E7=9A=84=20RocketMQ=20=E7=9A=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/RocketMQConfiguration.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java new file mode 100644 index 000000000..a9f2497f9 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -0,0 +1,151 @@ +package cn.axzo.workflow.starter; + +import cn.axzo.framework.rocketmq.BaseListener; +import cn.axzo.framework.rocketmq.DefaultEventConsumer; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandlerRepository; +import cn.axzo.framework.rocketmq.EventProducer; +import cn.axzo.framework.rocketmq.RocketMQEventProducer; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; +import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; +import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.spring.annotation.ConsumeMode; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * 配置 RocketMQ 事件监听器 + * + * @author wangli + * @since 2024/5/30 14:05 + */ +@Configuration(proxyBeanMethods = false) +public class RocketMQConfiguration { + private final Logger log = LoggerFactory.getLogger(RocketMQConfiguration.class); + + private static final String DEFAULT_MODULE = "workflowEngine"; + private static final String DEFAULT_EVENT = "topic_workflow_engine_"; + + @Value("${spring.application.name}") + private String applicationName; + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 客户端 RPC Retry 事件生产者 + * + * @param rocketMQTemplate + * @return + */ + @Bean + public EventProducer workflowEngineClientEventProducer(RocketMQTemplate rocketMQTemplate) { + return new RocketMQEventProducer(rocketMQTemplate, + DEFAULT_MODULE, + applicationName, + EventProducer.Context.builder() + .meta(RocketMQEventProducer.RocketMQMessageMeta.builder() + .topic(DEFAULT_EVENT + activeProfile) + .build()) + .headers(new HashMap<>()) + .syncSending(Boolean.TRUE) + .exceptionHandler(context -> { + log.error("MQ, send event error: {}, event: {}", + context.getThrowable().getCause().getMessage(), + context.getEvent().toPrettyJsonString(), + context.getThrowable()); + }) + .build(), + (event, context) -> { + // 调用 Rocket 发送 API 后的回调,不代表真实发送 + } + ); + } + + @Bean + public RpcInvokeEventProducer rpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer, + Environment environment) { + return new RpcInvokeEventProducer(workflowEngineClientEventProducer, environment); + } + + @Bean + @ConditionalOnClass(EventHandlerRepository.class) + public EventHandlerRepository eventHandlerRepository() { + return new EventHandlerRepository((ex, logText) -> { + log.warn("MQ, handle warning {}", logText, ex); + if (Objects.nonNull(ex)) { + throw new RuntimeException(ex); + } + }); + } + + @Bean + @ConditionalOnClass(EventConsumer.class) + public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { + Consumer callback = eventWrapper -> { + if (eventWrapper.isHandled()) { + // 只收集被App真正消费的消息. + //String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY); + } + }; + return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); + } + + @Component + @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", + consumerGroup = "GID_${spring.application.name}_workflow_engine_${MY_POD_NAMESPACE:debugging}_consumer", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + @Resource + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + + @Bean(initMethod = "init") + public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(EventConsumer eventConsumer) { + return new WorkflowEngineBroadcastEventListener(eventConsumer); + } + + @Component + @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", + consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", + consumeMode = ConsumeMode.CONCURRENTLY, + nameServer = "${rocketmq.name-server}" + ) + public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { + @Resource + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + + @Bean(initMethod = "init") + public WorkflowEngineClientRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer, + Environment environment) { + return new WorkflowEngineClientRetryEventListener(eventConsumer, environment); + } + +} From e8b0980a0e1e84c63d586a1a158fe9e8ccf400c3 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:48:08 +0800 Subject: [PATCH 024/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20RPC=20=E8=B0=83=E7=94=A8=E5=8A=A8=E4=BD=9C=E7=9A=84?= =?UTF-8?q?=20MQ=20=E4=BA=8B=E4=BB=B6=E7=94=9F=E4=BA=A7=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../producer/RpcInvokeEventProducer.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index 8f5d2e30c..d319ec170 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -2,11 +2,12 @@ package cn.axzo.workflow.starter.mq.retry.producer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventProducer; - -import java.io.Serializable; +import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; +import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; +import org.springframework.core.env.Environment; /** - * TODO + * RPC 的调用动作的 MQ 事件生产者 * * @author wangli * @since 2024/5/22 10:02 @@ -14,22 +15,25 @@ import java.io.Serializable; public class RpcInvokeEventProducer { private final EventProducer workflowEngineClientEventProducer; + private final String currentApplicationName; - public RpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer) { + public RpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer, Environment environment) { this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; + this.currentApplicationName = environment.getProperty("spring.application.name"); } /** * 发送 RPC 调用的事件 * - * @param shardingKey - * @param eventCode - * @param data + * @param eventEnum {@link WorkflowEngineEventEnum} + * @param data {@link WorkflowEngineStarterRpcInvokeDTO} */ - public void send(String shardingKey, Event.EventCode eventCode, Serializable data) { + public void send(WorkflowEngineEventEnum eventEnum, WorkflowEngineStarterRpcInvokeDTO data) { workflowEngineClientEventProducer.send(Event.builder() - .shardingKey(shardingKey) - .eventCode(eventCode) + .shardingKey(data.getMethodName()) + .eventCode(eventEnum.getEventCode(currentApplicationName)) + .targetId(data.getMethodName()) + .targetType(eventEnum.getTag()) .data(data) .build()); } From 185109d55bc0d805708a55fc3d2fe198edec372f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:49:45 +0800 Subject: [PATCH 025/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20RPC=20=E5=8A=A8=E4=BD=9C=E7=9A=84=20MQ=20=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=E8=80=85=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/RocketMQConfiguration.java | 8 ++--- ...orkflowEngineClientRetryEventListener.java | 33 ----------------- ...rkflowEngineStarterRetryEventListener.java | 36 +++++++++++++++++++ 3 files changed, 40 insertions(+), 37 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java index a9f2497f9..3c285ec3a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -7,7 +7,7 @@ import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; -import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; +import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; @@ -143,9 +143,9 @@ public class RocketMQConfiguration { } @Bean(initMethod = "init") - public WorkflowEngineClientRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer, - Environment environment) { - return new WorkflowEngineClientRetryEventListener(eventConsumer, environment); + public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer, + Environment environment) { + return new WorkflowEngineStarterRetryEventListener(eventConsumer, environment); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java deleted file mode 100644 index 605436cea..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineClientRetryEventListener.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.axzo.workflow.starter.mq.retry.consumer; - -import cn.axzo.framework.rocketmq.Event; -import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * TODO - * - * @author wangli - * @since 2024/5/21 16:28 - */ -public class WorkflowEngineClientRetryEventListener implements EventHandler { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineClientRetryEventListener.class); - private EventConsumer eventConsumer; - - public WorkflowEngineClientRetryEventListener(EventConsumer eventConsumer) { - this.eventConsumer = eventConsumer; - } - - public void init() { - eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); - } - - @Override - public void onEvent(Event event, EventConsumer.Context context) { - - } - -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java new file mode 100644 index 000000000..bf5c63805 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.starter.mq.retry.consumer; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +/** + * RPC 动作事件的 MQ 消费者 + * + * @author wangli + * @since 2024/5/21 16:28 + */ +public class WorkflowEngineStarterRetryEventListener implements EventHandler { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryEventListener.class); + private final EventConsumer eventConsumer; + private final String currentApplicationName; + + public WorkflowEngineStarterRetryEventListener(EventConsumer eventConsumer, Environment environment) { + this.eventConsumer = eventConsumer; + this.currentApplicationName = environment.getProperty("spring.application.name"); + } + + public void init() { + eventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); + } + + @Override + public void onEvent(Event event, EventConsumer.Context context) { + log.info("WorkflowEngineClientRetryEventListener onEvent: {}", event.toPrettyJsonString()); + } + +} From 67f33da824ac4a5253446e930ac6cf8696da5b8d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:50:09 +0800 Subject: [PATCH 026/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=B2=BE?= =?UTF-8?q?=E7=AE=80Starter=20=E7=9A=84=E4=B8=BB=E8=A6=81=20AutoConfigurat?= =?UTF-8?q?ion=20=E9=85=8D=E7=BD=AE=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 131 +----------------- 1 file changed, 2 insertions(+), 129 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index b8ecb0fe3..41de24233 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,35 +1,15 @@ package cn.axzo.workflow.starter; -import cn.axzo.framework.rocketmq.BaseListener; -import cn.axzo.framework.rocketmq.DefaultEventConsumer; -import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; -import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; -import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineClientRetryEventListener; -import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.axzo.workflow.starter.service.WorkflowEngineServiceFacade; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.spring.annotation.ConsumeMode; -import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; -import org.apache.rocketmq.spring.core.RocketMQListener; -import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.Objects; -import java.util.function.Consumer; +import org.springframework.context.annotation.Import; /** * Workflow Engine Auto Configuration @@ -40,17 +20,10 @@ import java.util.function.Consumer; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) @EnableFeignClients(clients = {WorkflowCoreService.class}) +@Import(RocketMQConfiguration.class) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); - private static final String DEFAULT_MODULE = "workflowEngine"; - private static final String DEFAULT_EVENT = "topic_workflow_engine"; - - @Value("${spring.application.name}") - private String applicationName; - @Value("${spring.profiles.active:dev}") - private String activeProfile; - @Bean public WorkflowEngineServiceFacade workflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, @@ -58,104 +31,4 @@ public class WorkflowEngineStarterAutoConfiguration { return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineStarterProperties); } - - /** - * 客户端 RPC Retry 事件生产者 - * - * @param rocketMQTemplate - * @return - */ - @Bean - public EventProducer workflowEngineClientEventProducer(RocketMQTemplate rocketMQTemplate) { - return new RocketMQEventProducer(rocketMQTemplate, - DEFAULT_MODULE, - applicationName, - EventProducer.Context.builder() - .meta(RocketMQEventProducer.RocketMQMessageMeta.builder() - .topic(DEFAULT_EVENT + activeProfile) - .build()) - .headers(new HashMap<>()) - .syncSending(Boolean.TRUE) - .exceptionHandler(context -> { - log.error("MQ, send event error: {}, event: {}", - context.getThrowable().getCause().getMessage(), - context.getEvent().toPrettyJsonString(), - context.getThrowable()); - }) - .build(), - (event, context) -> { - // 调用 Rocket 发送 API 后的回调,不代表真实发送 - } - ); - } - - @Bean - public RpcInvokeEventProducer rpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer) { - return new RpcInvokeEventProducer(workflowEngineClientEventProducer); - } - - @Bean - @ConditionalOnClass(EventHandlerRepository.class) - public EventHandlerRepository eventHandlerRepository() { - return new EventHandlerRepository((ex, logText) -> { - log.warn("MQ, handle warning {}", logText, ex); - if (Objects.nonNull(ex)) { - throw new RuntimeException(ex); - } - }); - } - - @Bean - @ConditionalOnClass(EventConsumer.class) - public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { - Consumer callback = eventWrapper -> { - if (eventWrapper.isHandled()) { - // 只收集被App真正消费的消息. - //String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY); - } - }; - return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); - } - - @Component - @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_consumer", - consumeMode = ConsumeMode.ORDERLY, - nameServer = "${rocketmq.name-server}" - ) - public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { - @Resource - private EventConsumer eventConsumer; - - @Override - public void onMessage(MessageExt message) { - super.onEvent(message, eventConsumer); - } - } - - @Bean(initMethod = "init") - public WorkflowEngineClientRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer) { - return new WorkflowEngineClientRetryEventListener(eventConsumer); - } - - @Component - @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_client_${spring.profiles.active}_consumer", - consumeMode = ConsumeMode.ORDERLY, - nameServer = "${rocketmq.name-server}" - ) - public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { - @Resource - private EventConsumer eventConsumer; - - @Override - public void onMessage(MessageExt message) { - super.onEvent(message, eventConsumer); - } - } - - @Bean(initMethod = "init") - public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(EventConsumer eventConsumer) { - return new WorkflowEngineBroadcastEventListener(eventConsumer); - } } From 3318ba36d4ce300e7b593b66cffb5e7743c0307e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:51:02 +0800 Subject: [PATCH 027/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20Starter=20=E4=B8=AD=20Feign=20=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/api/WorkflowCoreService.java | 4 ++-- ...=> WorkflowEngineStarterFeignConfiguration.java} | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/{WorkflowEngineStarterConfiguration.java => WorkflowEngineStarterFeignConfiguration.java} (70%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 2255fb285..d3a2420b4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -2,7 +2,7 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.starter.common.util.ThreadUtil; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterConfiguration; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; @@ -20,7 +20,7 @@ import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; */ @FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", - configuration = WorkflowEngineStarterConfiguration.class) + configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { @PostMapping("/api/process/instance/create") diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java similarity index 70% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index a8bbe4d88..a4ec7c975 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.RequestInterceptor; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; @@ -16,11 +17,13 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_ * @author wangli * @since 2024/5/28 23:17 */ -public class WorkflowEngineStarterConfiguration { +public class WorkflowEngineStarterFeignConfiguration { @Bean - public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, Client feignClient) { - return new ComplexInvokeClient(starterProperties, feignClient); + public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, + RpcInvokeEventProducer rpcInvokeEventProducer, + Client feignClient) { + return new ComplexInvokeClient(starterProperties, rpcInvokeEventProducer, feignClient); } @Bean @@ -33,8 +36,6 @@ public class WorkflowEngineStarterConfiguration { @Bean public FeignBuilderCustomizer workflowEngineFeignBuilderCustomizer() { - return builder -> { - builder.invocationHandlerFactory(new WorkflowEngineStarterInvocationHandlerFactory()); - }; + return builder -> builder.invocationHandlerFactory(new WorkflowEngineStarterInvocationHandlerFactory()); } } From 4605d462a72bc074d02b106376ae95955745396d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:51:29 +0800 Subject: [PATCH 028/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20RPC=20=E5=8A=A8=E4=BD=9C=20MQ=20=E7=9A=84=20EventCo?= =?UTF-8?q?de=20=E5=AE=9A=E4=B9=89=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/WorkflowEngineEventEnum.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java index 3a0980518..a74dcd261 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java @@ -11,7 +11,7 @@ import cn.axzo.framework.rocketmq.Event; public enum WorkflowEngineEventEnum { WORKFLOW_ENGINE_SERVER("workflow-engine", "workflow-engine-server", "引擎服务端事件"), - WORKFLOW_ENGINE_CLIENT("workflow-engine", "workflow-engine-client-%s", "引擎客户端事件"), + WORKFLOW_ENGINE_STARTER("workflow-engine", "workflow-engine-starter-%s", "引擎客户端事件"), ; private final String module; @@ -34,4 +34,16 @@ public enum WorkflowEngineEventEnum { return eventCode; } + public String getModule() { + return module; + } + + public String getTag() { + return tag; + } + + public String getDesc() { + return desc; + } + } From 84dad7e05e0d428eff7c0fd12e51f8508d2d625d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:51:50 +0800 Subject: [PATCH 029/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=20RPC=20=E5=8A=A8=E4=BD=9C=20MQ=20=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/WorkflowEngineStarterRpcInvokeDTO.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java new file mode 100644 index 000000000..a596cdd51 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java @@ -0,0 +1,65 @@ +package cn.axzo.workflow.common.model.response.mq; + +import java.io.Serializable; +import java.util.List; + +/** + * Starter RPC 调用事件模型 + * + * @author wangli + * @since 2024/5/30 11:21 + */ +public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { + private static final long serialVersionUID = -1L; + + private String className; + + private String methodName; + + private List parameterTypes; + + private String originUrl; + + private Object body; + + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public List getParameterTypes() { + return parameterTypes; + } + + public void setParameterTypes(List parameterTypes) { + this.parameterTypes = parameterTypes; + } + + public String getOriginUrl() { + return originUrl; + } + + public void setOriginUrl(String originUrl) { + this.originUrl = originUrl; + } + + public Object getBody() { + return body; + } + + public void setBody(Object body) { + this.body = body; + } +} From 93bd911c186ac2f5bff2823028c9eefd28d3c50e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:52:34 +0800 Subject: [PATCH 030/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=89=A9?= =?UTF-8?q?=E5=B1=95=20Feign=20=E7=9A=84=20Client=EF=BC=8C=E8=BE=BE?= =?UTF-8?q?=E5=88=B0=E5=8F=AF=E4=BB=A5=E5=90=8C=E6=AD=A5=E5=92=8C=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/ComplexInvokeClient.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 26238a071..a8d375314 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,9 +1,11 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.common.util.ThreadUtil; +import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.Request; import feign.Response; @@ -12,11 +14,16 @@ import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Stream; +import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; @@ -32,10 +39,14 @@ public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); private final WorkflowEngineStarterProperties starterProperties; + private final RpcInvokeEventProducer rpcInvokeEventProducer; private final Client feignClient; - public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, Client feignClient) { + public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, + RpcInvokeEventProducer rpcInvokeEventProducer, + Client feignClient) { this.starterProperties = starterProperties; + this.rpcInvokeEventProducer = rpcInvokeEventProducer; this.feignClient = feignClient; } @@ -46,7 +57,6 @@ public class ComplexInvokeClient implements Client { if (Objects.isNull(currentInvokeModeEnum)) { currentInvokeModeEnum = getDefaultInvokeMode(request); - ; } if (Objects.equals(SYNC, currentInvokeModeEnum)) { @@ -57,6 +67,17 @@ public class ComplexInvokeClient implements Client { headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); // TODO 发送 RPC 调用动作的 MQ 事件 + WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); + event.setClassName(request.requestTemplate().feignTarget().type().getName()); + event.setMethodName(request.requestTemplate().methodMetadata().method().getName()); + + List types = new ArrayList<>(); + Stream.of(request.requestTemplate().methodMetadata().method().getParameterTypes()).forEach(p -> types.add(p.getName())); + event.setParameterTypes(types); + + event.setOriginUrl(request.url()); + event.setBody(new String(request.body(), StandardCharsets.UTF_8)); + rpcInvokeEventProducer.send(WORKFLOW_ENGINE_STARTER, event); return Response.builder() .status(HttpStatus.OK.value()) From 37ea56b2978d55190ff58a41cde40118f8e70225 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 14:52:56 +0800 Subject: [PATCH 031/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E7=94=9F=E6=88=90=E7=9A=84=E5=8F=97=E9=99=90=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService_Gen.java | 418 +++++++++--------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java index 5c566a6c7..ac90f8bbb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java @@ -48,247 +48,247 @@ import java.util.List; import java.util.Map; public interface WorkflowCoreService_Gen { - @Operation( - summary = "待审核列表" - ) - @GetMapping("/api/process/task/page/todo") - CommonResponse> getTodoTaskPage( - @Validated @RequestBody BpmnTaskPageSearchDTO dto); + @Operation( + summary = "待审核列表" + ) + @GetMapping("/api/process/task/page/todo") + CommonResponse> getTodoTaskPage( + @Validated @RequestBody BpmnTaskPageSearchDTO dto); - @Operation( - summary = "已完成的审批列表" - ) - @GetMapping("/api/process/task/page/done") - CommonResponse> getDoneTaskPage( - @Validated @RequestBody BpmnTaskPageSearchDTO dto); + @Operation( + summary = "已完成的审批列表" + ) + @GetMapping("/api/process/task/page/done") + CommonResponse> getDoneTaskPage( + @Validated @RequestBody BpmnTaskPageSearchDTO dto); - @Operation( - summary = "获取指定流程实例的审批过程信息" - ) - @GetMapping("/api/process/task/list/flat") - CommonResponse> getTaskListFlatByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @Operation( + summary = "获取指定流程实例的审批过程信息" + ) + @GetMapping("/api/process/task/list/flat") + CommonResponse> getTaskListFlatByProcessInstanceId( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); - @Operation( - summary = "获取指定流程实例的审批过程信息" - ) - @GetMapping("/api/process/task/list/group") - CommonResponse> getTaskListGroupByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @Operation( + summary = "获取指定流程实例的审批过程信息" + ) + @GetMapping("/api/process/task/list/group") + CommonResponse> getTaskListGroupByProcessInstanceId( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); - @Operation( - summary = "获取实例正在审核的人列表" - ) - @GetMapping("/api/process/task/active/list") - CommonResponse> getActiveTasksByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + @Operation( + summary = "获取实例正在审核的人列表" + ) + @GetMapping("/api/process/task/active/list") + CommonResponse> getActiveTasksByProcessInstanceId( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @NotBlank(message = "租户不能为空") @RequestParam String tenantId); - @Operation( - summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件" - ) - @PostMapping("/api/process/task/approve") - CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + @Operation( + summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件" + ) + @PostMapping("/api/process/task/approve") + CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - @Operation( - summary = "批量同意" - ) - @PostMapping("/api/process/task/batch/approve") - CommonResponse batchApproveTask( - @Validated @RequestBody List dtos); + @Operation( + summary = "批量同意" + ) + @PostMapping("/api/process/task/batch/approve") + CommonResponse batchApproveTask( + @Validated @RequestBody List dtos); - @Operation( - summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件" - ) - @PostMapping("/api/process/task/reject") - CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + @Operation( + summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件" + ) + @PostMapping("/api/process/task/reject") + CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - @PostMapping("/api/process/task/batch/reject") - CommonResponse batchRejectTask( - @Validated @RequestBody List dtos); + @PostMapping("/api/process/task/batch/reject") + CommonResponse batchRejectTask( + @Validated @RequestBody List dtos); - @Operation( - summary = "直接修改审批任务的审批人" - ) - @PostMapping("/api/process/task/transfer") - CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); + @Operation( + summary = "直接修改审批任务的审批人" + ) + @PostMapping("/api/process/task/transfer") + CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); - @Operation( - summary = "批量修改审批任务的审批人" - ) - @PostMapping("/api/process/task/batch/transfer") - CommonResponse batchTransferTask( - @Validated @RequestBody List dtos); + @Operation( + summary = "批量修改审批任务的审批人" + ) + @PostMapping("/api/process/task/batch/transfer") + CommonResponse batchTransferTask( + @Validated @RequestBody List dtos); - @Operation( - summary = "审批流程评论" - ) - @PostMapping("/api/process/task/comment") - CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); + @Operation( + summary = "审批流程评论" + ) + @PostMapping("/api/process/task/comment") + CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); - @Operation( - summary = "添加附件" - ) - @PostMapping("/api/process/task/attachment") - CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); + @Operation( + summary = "添加附件" + ) + @PostMapping("/api/process/task/attachment") + CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); - @Operation( - summary = "审批流程加签" - ) - @PostMapping("/api/process/task/countersign") - CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); + @Operation( + summary = "审批流程加签" + ) + @PostMapping("/api/process/task/countersign") + CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); - @Operation( - summary = "审批流程催办" - ) - @PostMapping("/api/process/task/remind") - CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); + @Operation( + summary = "审批流程催办" + ) + @PostMapping("/api/process/task/remind") + CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); - @Operation( - summary = "创建机器人节点, 暂停流程任务" - ) - @PostMapping("/api/process/task/robot/create") - CommonResponse createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); + @Operation( + summary = "创建机器人节点, 暂停流程任务" + ) + @PostMapping("/api/process/task/robot/create") + CommonResponse createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); - @Operation( - summary = "完成机器人节点, 继续流程任务" - ) - @PostMapping("/api/process/task/robot/complete") - CommonResponse completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); + @Operation( + summary = "完成机器人节点, 继续流程任务" + ) + @PostMapping("/api/process/task/robot/complete") + CommonResponse completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); - @Operation( - summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" - ) - @GetMapping("/api/process/task/find") - CommonResponse findTaskIdByInstanceIdAndPersonId( - @RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, - @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + @Operation( + summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" + ) + @GetMapping("/api/process/task/find") + CommonResponse findTaskIdByInstanceIdAndPersonId( + @RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, + @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); - @Operation( - summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" - ) - @GetMapping("/api/process/task/batch/find") - CommonResponse> findTaskIdByInstanceIdsAndPersonId( - @RequestParam(required = false) @NotNull(message = "流程实例 ID列表 不能为空") List processInstanceIds, - @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + @Operation( + summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" + ) + @GetMapping("/api/process/task/batch/find") + CommonResponse> findTaskIdByInstanceIdsAndPersonId( + @RequestParam(required = false) @NotNull(message = "流程实例 ID列表 不能为空") List processInstanceIds, + @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); - @Operation( - summary = "查询所有的审批流" - ) - @PostMapping("/api/process/instance/page/all") - CommonResponse> getAllProcessInstancePage( - @Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); + @Operation( + summary = "查询所有的审批流" + ) + @PostMapping("/api/process/instance/page/all") + CommonResponse> getAllProcessInstancePage( + @Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); - @Operation( - summary = "我发起的审批列表" - ) - @PostMapping("/api/process/instance/page/my") - CommonResponse> getMyProcessInstancePage( - @Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); + @Operation( + summary = "我发起的审批列表" + ) + @PostMapping("/api/process/instance/page/my") + CommonResponse> getMyProcessInstancePage( + @Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); - @Operation( - summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件" - ) - @PostMapping("/api/process/instance/create") - CommonResponse createProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + @Operation( + summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件" + ) + @PostMapping("/api/process/instance/create") + CommonResponse createProcessInstance( + @Validated @RequestBody BpmnProcessInstanceCreateDTO dto); - @Operation( - summary = "创建审批流程并带上表单" - ) - @PostMapping("/api/process/instance/form/create") - CommonResponse createProcessInstanceWith( - @Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); + @Operation( + summary = "创建审批流程并带上表单" + ) + @PostMapping("/api/process/instance/form/create") + CommonResponse createProcessInstanceWith( + @Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); - @Operation( - summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件" - ) - @DeleteMapping("/api/process/instance/cancel") - CommonResponse cancelProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCancelDTO dto); + @Operation( + summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件" + ) + @DeleteMapping("/api/process/instance/cancel") + CommonResponse cancelProcessInstance( + @Validated @RequestBody BpmnProcessInstanceCancelDTO dto); - @Operation( - summary = "中止流程实例" - ) - @DeleteMapping("/api/process/instance/abort") - CommonResponse abortProcessInstance( - @Validated @RequestBody BpmnProcessInstanceAbortDTO dto); + @Operation( + summary = "中止流程实例" + ) + @DeleteMapping("/api/process/instance/abort") + CommonResponse abortProcessInstance( + @Validated @RequestBody BpmnProcessInstanceAbortDTO dto); - @Operation( - summary = "批量中止流程实例" - ) - @DeleteMapping("/api/process/instance/batch/abort") - CommonResponse batchAbortProcessInstance( - @Validated @RequestBody List dtos); + @Operation( + summary = "批量中止流程实例" + ) + @DeleteMapping("/api/process/instance/batch/abort") + CommonResponse batchAbortProcessInstance( + @Validated @RequestBody List dtos); - @Operation( - summary = "抄送流程实例" - ) - @PostMapping("/api/process/instance/carbon-copy") - CommonResponse carbonCopyProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); + @Operation( + summary = "抄送流程实例" + ) + @PostMapping("/api/process/instance/carbon-copy") + CommonResponse carbonCopyProcessInstance( + @Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); - @Operation( - summary = "获得流程实例" - ) - @GetMapping("/api/process/instance/get") - CommonResponse getProcessInstanceVO( - @Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + @Operation( + summary = "获得流程实例" + ) + @GetMapping("/api/process/instance/get") + CommonResponse getProcessInstanceVO( + @Validated @RequestBody BpmnProcessInstanceQueryDTO dto); - @Operation( - summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" - ) - @PutMapping("/api/process/instance/status/update") - CommonResponse updateProcessStatus( - @NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, - @NotNull(message = "状态不能为空") @RequestParam Integer status); + @Operation( + summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" + ) + @PutMapping("/api/process/instance/status/update") + CommonResponse updateProcessStatus( + @NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, + @NotNull(message = "状态不能为空") @RequestParam Integer status); - @Operation( - summary = "获取审批流程实例的运行图" - ) - @GetMapping("/api/process/instance/graphical") - CommonResponse processInstanceGraphical( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @Operation( + summary = "获取审批流程实例的运行图" + ) + @GetMapping("/api/process/instance/graphical") + CommonResponse processInstanceGraphical( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); - @Operation( - summary = "推断指定流程实例的所有节点执行顺序" - ) - @GetMapping("/api/process/instance/node/forecasting") - CommonResponse> processInstanceNodeForecast( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @Operation( + summary = "推断指定流程实例的所有节点执行顺序" + ) + @GetMapping("/api/process/instance/node/forecasting") + CommonResponse> processInstanceNodeForecast( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); - @Operation( - summary = "推断指定流程实例的过滤掉部分节点执行顺序" - ) - @GetMapping("/api/process/instance/node/filter/forecasting") - CommonResponse> processInstanceFilterNodeForecast( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId, - @RequestParam(required = false, defaultValue = "false") Boolean allNode, - @Nullable @RequestParam(required = false) List nodeDefinitionKeys); + @Operation( + summary = "推断指定流程实例的过滤掉部分节点执行顺序" + ) + @GetMapping("/api/process/instance/node/filter/forecasting") + CommonResponse> processInstanceFilterNodeForecast( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId, + @RequestParam(required = false, defaultValue = "false") Boolean allNode, + @Nullable @RequestParam(required = false) List nodeDefinitionKeys); - @Operation( - summary = "获取指定流程实例的流程变量" - ) - @GetMapping("/api/process/instance/cooperation-org") - CommonResponse> getProcessVariables( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @Operation( + summary = "获取指定流程实例的流程变量" + ) + @GetMapping("/api/process/instance/cooperation-org") + CommonResponse> getProcessVariables( + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); - @Operation( - summary = "查询实例的租户集合" - ) - @GetMapping("/api/process/instance/tenant/ids") - CommonResponse> getTenantIds(); + @Operation( + summary = "查询实例的租户集合" + ) + @GetMapping("/api/process/instance/tenant/ids") + CommonResponse> getTenantIds(); - @Operation( - summary = "校验指定流程实例下,是否存在指定的审批人" - ) - @PostMapping("/api/process/instance/check/approver") - CommonResponse checkInstanceApprover( - @Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); + @Operation( + summary = "校验指定流程实例下,是否存在指定的审批人" + ) + @PostMapping("/api/process/instance/check/approver") + CommonResponse checkInstanceApprover( + @Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); } From cab614041e5d26930a77f364ee854b2d2f850b63 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 30 May 2024 16:51:56 +0800 Subject: [PATCH 032/210] =?UTF-8?q?update=20-=20REQ-2516-=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0Listener=E6=89=A7=E8=A1=8C=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/RocketMQConfiguration.java | 6 --- ...orkflowEngineStarterAutoConfiguration.java | 33 +++++++++++++ .../listener/MessageNotificationListener.java | 14 ++++++ .../listener/ProcessActivityListener.java | 36 +++++++++++++- .../consumer/InnerActivityEventListener.java | 49 ++++++++++++++++++- .../consumer/InnerNoticeEventListener.java | 30 ++++++++++++ .../WorkflowEngineBroadcastEventListener.java | 38 ++++++++++---- .../broadcast/consumer/WorkflowListener.java | 11 +++++ .../starter/mq/execute/ListenerExecutor.java | 8 +++ .../mq/execute/ListenerExecutorImpl.java | 19 +++++++ .../AbstractListenerInterceptor.java | 16 ++++++ .../interceptor/ExecuteInterceptor.java | 14 ++++++ .../execute/interceptor/ExecutorInvoker.java | 24 +++++++++ .../execute/interceptor/LogInterceptor.java | 25 ++++++++++ .../execute/interceptor/RetryInterceptor.java | 49 +++++++++++++++++++ 15 files changed, 354 insertions(+), 18 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java index 3c285ec3a..a9fac942d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -6,7 +6,6 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import org.apache.rocketmq.common.message.MessageExt; @@ -121,11 +120,6 @@ public class RocketMQConfiguration { } } - @Bean(initMethod = "init") - public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(EventConsumer eventConsumer) { - return new WorkflowEngineBroadcastEventListener(eventConsumer); - } - @Component @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 41de24233..0f559a499 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,8 +1,16 @@ package cn.axzo.workflow.starter; +import cn.axzo.framework.domain.ServiceException; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutorImpl; +import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; +import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; +import cn.axzo.workflow.starter.mq.execute.interceptor.LogInterceptor; +import cn.axzo.workflow.starter.mq.execute.interceptor.RetryInterceptor; import cn.axzo.workflow.starter.service.WorkflowEngineServiceFacade; +import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -11,6 +19,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import java.util.ArrayList; +import java.util.List; + /** * Workflow Engine Auto Configuration * @@ -31,4 +42,26 @@ public class WorkflowEngineStarterAutoConfiguration { return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineStarterProperties); } + @Bean + public ListenerExecutor initListenerExecutor(List additionalInterceptors) { + List interceptors = new ArrayList<>(); + interceptors.add(new LogInterceptor()); + interceptors.add(new RetryInterceptor()); + if (!CollectionUtils.isEmpty(additionalInterceptors)) { + additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); + } + interceptors.add(new ExecutorInvoker()); + return new ListenerExecutorImpl(initInterceptorChain(interceptors)); + } + + public ExecuteInterceptor initInterceptorChain(List chain) { + if (chain == null || chain.isEmpty()) { + throw new ServiceException("invalid command interceptor chain configuration: " + chain); + } + for (int i = 0; i < chain.size() - 1; i++) { + chain.get(i).setNext(chain.get(i + 1)); + } + return chain.get(0); + + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java index 615dd1cc0..d3ea96dfc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java @@ -1,5 +1,7 @@ package cn.axzo.workflow.starter.listener; +import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; + /** * TODO * @@ -7,4 +9,16 @@ package cn.axzo.workflow.starter.listener; * @since 2024/5/27 16:25 */ public interface MessageNotificationListener { + + void pushNotice(MessagePushDTO messagePushDTO); + + void pushPending(MessagePushDTO messagePushDTO); + + void completePending(MessagePushDTO messagePushDTO); + + void rollbackPending(MessagePushDTO messagePushDTO); + + void carbonCopy(MessagePushDTO messagePushDTO); + + void carbonCopyComplete(MessagePushDTO messagePushDTO); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java index 0c3ee9f98..78d55f7d9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java @@ -1,10 +1,42 @@ package cn.axzo.workflow.starter.listener; +import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; + /** - * TODO - * * @author wangli * @since 2024/5/27 16:25 */ public interface ProcessActivityListener { + + /** + * 节点已启动 + * + * @param activityDTO 入参 + */ + default void onStart(ProcessActivityDTO activityDTO) { + } + + /** + * 节点等待业务指定审批人 + * + * @param activityDTO 入参 + */ + default void onWaitAssignee(ProcessActivityDTO activityDTO) { + } + + /** + * 节点已完成 + * + * @param activityDTO 入参 + */ + default void onTake(ProcessActivityDTO activityDTO) { + } + + /** + * 节点已取消 + * + * @param activityDTO 入参 + */ + default void onEnd(ProcessActivityDTO activityDTO) { + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 4708c5b3a..fc3be696d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -1,18 +1,28 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; +import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; +import cn.axzo.workflow.starter.listener.ProcessActivityListener; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.List; +import java.util.function.Consumer; /** * @author wangli * @since 2024/5/21 15:51 */ -public class InnerActivityEventListener { +@Component +public class InnerActivityEventListener implements WorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( ProcessActivityEventEnum.PROCESS_ACTIVITY_START.getEventCode(), @@ -21,5 +31,42 @@ public class InnerActivityEventListener { ProcessActivityEventEnum.PROCESS_ACTIVITY_END.getEventCode() ); + @Autowired + private List activityListeners; + @Autowired + private ListenerExecutor listenerExecutor; + + @Override + public void handEvent(Event event, EventConsumer.Context context) { + if (!CollectionUtils.isEmpty(activityListeners)) { + ProcessActivityDTO activityDTO = JSON.parseObject(event.getData().toString(), ProcessActivityDTO.class); + ProcessActivityEventEnum type = activityDTO.getType(); + for (ProcessActivityListener activityListener : activityListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_ACTIVITY_START: + consumer = activityListener::onStart; + break; + case PROCESS_ACTIVITY_WAIT_ASSIGNEE: + consumer = activityListener::onWaitAssignee; + break; + case PROCESS_ACTIVITY_TAKE: + consumer = activityListener::onTake; + break; + case PROCESS_ACTIVITY_END: + consumer = activityListener::onEnd; + break; + default: + log.warn("unknown process activity event type: {}", type); + } + listenerExecutor.execute(consumer, activityDTO); + } + } + } + + @Override + public boolean support(Event event) { + return event != null && SUPPORTED_EVENT_CODES.contains(event.getEventCode()); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java index 83d535a10..1508fed01 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; +import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import cn.axzo.workflow.starter.listener.MessageNotificationListener; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; @@ -29,6 +30,35 @@ public class InnerNoticeEventListener { public static void main(String[] args) { MessageNotificationListener listener = new MessageNotificationListener() { + @Override + public void pushNotice(MessagePushDTO messagePushDTO) { + } + + @Override + public void pushPending(MessagePushDTO messagePushDTO) { + + } + + @Override + public void completePending(MessagePushDTO messagePushDTO) { + + } + + @Override + public void rollbackPending(MessagePushDTO messagePushDTO) { + + } + + @Override + public void carbonCopy(MessagePushDTO messagePushDTO) { + + } + + @Override + public void carbonCopyComplete(MessagePushDTO messagePushDTO) { + + } + public int hashCode() { return super.hashCode(); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 7f619176e..8c5741f5e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -3,8 +3,15 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; +import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; /** * TODO @@ -12,23 +19,36 @@ import org.slf4j.LoggerFactory; * @author wangli * @since 2024/5/21 15:50 */ -public class WorkflowEngineBroadcastEventListener implements EventHandler { +@Component +public class WorkflowEngineBroadcastEventListener implements EventHandler, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastEventListener.class); - private EventConsumer eventConsumer; + private final EventConsumer eventConsumer; + private final List workflowListeners; - public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer) { + public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, List workflowListeners) { this.eventConsumer = eventConsumer; + this.workflowListeners = workflowListeners; } - public void init() { + @Override + public void onEvent(Event event, EventConsumer.Context context) { + MessagePushDTO messagePushDTO = JSON.parseObject(event.getData().toString(), MessagePushDTO.class); + if (Objects.isNull(messagePushDTO)) { + log.warn("AllMessagePushEventHandler MessagePushDTO is null"); + return; + } + for (WorkflowListener workflowListener : workflowListeners) { + if (workflowListener.support(event)) { + workflowListener.handEvent(event, context); + } + } + } + + @Override + public void afterPropertiesSet() throws Exception { eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); } - - @Override - public void onEvent(Event event, EventConsumer.Context context) { - - } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java new file mode 100644 index 000000000..4f09cb561 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java @@ -0,0 +1,11 @@ +package cn.axzo.workflow.starter.mq.broadcast.consumer; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; + +public interface WorkflowListener { + + void handEvent(Event event, EventConsumer.Context context); + + boolean support(Event event); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java new file mode 100644 index 000000000..b7de37988 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java @@ -0,0 +1,8 @@ +package cn.axzo.workflow.starter.mq.execute; + +import java.util.function.Consumer; + +public interface ListenerExecutor { + + void execute(Consumer command, T t); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java new file mode 100644 index 000000000..ef39ac4eb --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java @@ -0,0 +1,19 @@ +package cn.axzo.workflow.starter.mq.execute; + +import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; + +import java.util.function.Consumer; + +public class ListenerExecutorImpl implements ListenerExecutor { + + private final ExecuteInterceptor firstExecuteInterceptor; + + public ListenerExecutorImpl(ExecuteInterceptor firstExecuteInterceptor) { + this.firstExecuteInterceptor = firstExecuteInterceptor; + } + + @Override + public void execute(Consumer command, T t) { + firstExecuteInterceptor.execute(this, command, t); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java new file mode 100644 index 000000000..a033812f3 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java @@ -0,0 +1,16 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +public abstract class AbstractListenerInterceptor implements ExecuteInterceptor { + + protected ExecuteInterceptor next; + + @Override + public ExecuteInterceptor getNext() { + return next; + } + + @Override + public void setNext(ExecuteInterceptor next) { + this.next = next; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java new file mode 100644 index 000000000..bacc59e73 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java @@ -0,0 +1,14 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; + +import java.util.function.Consumer; + +public interface ExecuteInterceptor { + + void execute(ListenerExecutor executor, Consumer consumer, T t); + + ExecuteInterceptor getNext(); + + void setNext(ExecuteInterceptor next); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java new file mode 100644 index 000000000..fadcb9df5 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java @@ -0,0 +1,24 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; + +import java.util.function.Consumer; + +public class ExecutorInvoker extends AbstractListenerInterceptor { + + @Override + public void execute(ListenerExecutor executor, Consumer consumer, T t) { + consumer.accept(t); + } + + @Override + public ExecuteInterceptor getNext() { + return null; + } + + @Override + public void setNext(ExecuteInterceptor next) { + throw new UnsupportedOperationException("ExecutorInvoker must be the last interceptor in the chain"); + } + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java new file mode 100644 index 000000000..7961f0f73 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StopWatch; + +import java.util.function.Consumer; + +public class LogInterceptor extends AbstractListenerInterceptor { + private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class); + + @Override + public void execute(ListenerExecutor executor, Consumer consumer, T t) { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + LOGGER.debug("--- starting {} ----", executor.getClass().getSimpleName()); + try { + getNext().execute(executor, consumer, t); + } finally { + stopWatch.stop(); + LOGGER.debug("--- {} finished ,timeCost:{} ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); + } + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java new file mode 100644 index 000000000..9758b5aaf --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java @@ -0,0 +1,49 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +import cn.axzo.framework.domain.ServiceException; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import lombok.Getter; +import lombok.Setter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.function.Consumer; + +@Getter +@Setter +public class RetryInterceptor extends AbstractListenerInterceptor { + + private static final Logger LOGGER = LoggerFactory.getLogger(RetryInterceptor.class); + + protected int numOfRetries = 3; + protected int waitTimeInMs = 50; + protected int waitIncreaseFactor = 5; + + @Override + public void execute(ListenerExecutor executor, Consumer consumer, T t) { + long waitTime = waitTimeInMs; + int failedAttempts = 0; + do { + if (failedAttempts > 0) { + LOGGER.info("Waiting for {}ms before retrying the command.", waitTime); + waitBeforeRetry(waitTime); + waitTime *= waitIncreaseFactor; + } + try { + getNext().execute(executor, consumer, t); + } catch (Exception e) { + LOGGER.info("Caught exception: {}", e.getMessage(), e); + } + failedAttempts++; + } while (failedAttempts <= numOfRetries); + throw new ServiceException(numOfRetries + " retries failed with Exception. Giving up."); + } + + protected void waitBeforeRetry(long waitTime) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + LOGGER.debug(" interrupted while waiting for a retry."); + } + } +} From 4062f0dbe42c4048475c1fdb13886d92ca97fbf1 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 18:10:11 +0800 Subject: [PATCH 033/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=90=8C=E6=AD=A5=E5=BC=82=E6=AD=A5=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E7=9A=84=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/RocketMQConfiguration.java | 10 +- ...orkflowEngineStarterAutoConfiguration.java | 8 - ...rkflowEngineStarterFeignConfiguration.java | 15 +- ...orkflowEngineStarterInvocationHandler.java | 5 +- ...rkflowEngineStarterRetryEventListener.java | 61 +- .../service/WorkflowEngineServiceFacade.java | 71 --- .../service/impl/AsynchronousService.java | 18 - .../service/impl/SynchronousService.java | 526 ------------------ 8 files changed, 84 insertions(+), 630 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java index a9fac942d..2ad4b1d6a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -6,6 +6,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; +import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import org.apache.rocketmq.common.message.MessageExt; @@ -105,7 +106,7 @@ public class RocketMQConfiguration { } @Component - @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", + @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${MY_POD_NAMESPACE:debugging}_consumer", consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" @@ -121,7 +122,7 @@ public class RocketMQConfiguration { } @Component - @RocketMQMessageListener(topic = DEFAULT_EVENT + "_${spring.profiles.active}", + @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, nameServer = "${rocketmq.name-server}" @@ -138,8 +139,9 @@ public class RocketMQConfiguration { @Bean(initMethod = "init") public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer, - Environment environment) { - return new WorkflowEngineStarterRetryEventListener(eventConsumer, environment); + Environment environment, + WorkflowCoreService workflowCoreService) { + return new WorkflowEngineStarterRetryEventListener(eventConsumer, environment, workflowCoreService); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 0f559a499..37165542d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,7 +1,6 @@ package cn.axzo.workflow.starter; import cn.axzo.framework.domain.ServiceException; -import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import cn.axzo.workflow.starter.mq.execute.ListenerExecutorImpl; @@ -9,7 +8,6 @@ import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; import cn.axzo.workflow.starter.mq.execute.interceptor.LogInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.RetryInterceptor; -import cn.axzo.workflow.starter.service.WorkflowEngineServiceFacade; import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,12 +34,6 @@ public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); - @Bean - public WorkflowEngineServiceFacade workflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, - WorkflowEngineStarterProperties workflowEngineStarterProperties) { - return new WorkflowEngineServiceFacade(workflowEngineClientEventProducer, workflowEngineStarterProperties); - } - @Bean public ListenerExecutor initListenerExecutor(List additionalInterceptors) { List interceptors = new ArrayList<>(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index a4ec7c975..2935f4e34 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -4,10 +4,14 @@ import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.RequestInterceptor; +import feign.Target; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; +import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; +import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; +import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; @@ -27,13 +31,22 @@ public class WorkflowEngineStarterFeignConfiguration { } @Bean - public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment) { + public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, + Environment environment, + String serviceVersion) { return template -> { template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); template.header(STARTER_INVOKE_MODE, starterProperties.getInvokeMode().name()); + Target.HardCodedTarget target = (Target.HardCodedTarget) template.feignTarget(); + String apiClassPath = target.type().getName(); + if (apiClassPath.contains("cn.axzo.workflow.starter.api")) { + template.header(HEADER_HTTP_CLIENT, HEADER_HTTP_CLIENT_VALUE); + template.header(HEADER_API_VERSION, serviceVersion); + } }; } + @Bean public FeignBuilderCustomizer workflowEngineFeignBuilderCustomizer() { return builder -> builder.invocationHandlerFactory(new WorkflowEngineStarterInvocationHandlerFactory()); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java index ef8ce52ba..583b5b96c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -24,7 +24,6 @@ public class WorkflowEngineStarterInvocationHandler implements InvocationHandler this.dispatch = dispatch; } - @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("equals".equals(method.getName())) { @@ -62,4 +61,8 @@ public class WorkflowEngineStarterInvocationHandler implements InvocationHandler public String toString() { return target.toString(); } + + public Class getTargetClass() { + return target.getClass(); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index bf5c63805..4b09f8a6c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -4,10 +4,22 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; +import cn.axzo.workflow.starter.api.WorkflowCoreService; +import com.alibaba.fastjson.JSON; +import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + /** * RPC 动作事件的 MQ 消费者 * @@ -17,20 +29,67 @@ import org.springframework.core.env.Environment; public class WorkflowEngineStarterRetryEventListener implements EventHandler { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryEventListener.class); private final EventConsumer eventConsumer; + private final Environment environment; private final String currentApplicationName; + private final WorkflowCoreService workflowCoreService; + private final Map methodCache = new HashMap<>(); - public WorkflowEngineStarterRetryEventListener(EventConsumer eventConsumer, Environment environment) { + public WorkflowEngineStarterRetryEventListener(EventConsumer eventConsumer, Environment environment, WorkflowCoreService workflowCoreService) { this.eventConsumer = eventConsumer; + this.environment = environment; this.currentApplicationName = environment.getProperty("spring.application.name"); + this.workflowCoreService = workflowCoreService; + parseWorkflowCoreService(); + } + + private void parseWorkflowCoreService() { + Class coreService = (Class) workflowCoreService.getClass().getGenericInterfaces()[0]; + FeignClient feignClient = AnnotationUtils.findAnnotation(coreService, FeignClient.class); + if (Objects.isNull(feignClient)) { + throw new IllegalStateException("WorkflowCoreService 配置错误,没有找到 FeignClient 注解"); + } + String parsedFeignContextUrl = resolveExpression(feignClient.url()); + + Method[] methods = coreService.getDeclaredMethods(); + for (Method method : methods) { + methodCache.put(method.getName(), method); + } + } + + private String resolveExpression(String expression) { + // 假设表达式格式是 ${property:defaultValue} + if (expression != null && expression.startsWith("${") && expression.endsWith("}")) { + String content = expression.substring(2, expression.length() - 1); // 去除 ${ 和 } + String[] parts = content.split(":", 2); // 分割属性和默认值 + String property = parts[0]; + String defaultValue = parts.length > 1 ? parts[1] : null; + // 尝试从环境中获取属性值,如果未找到则使用默认值 + return environment.getProperty(property, defaultValue != null ? defaultValue : ""); + } + // 如果表达式格式不匹配,直接返回原表达式或处理错误情况 + return expression; } public void init() { eventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); } + @SneakyThrows @Override public void onEvent(Event event, EventConsumer.Context context) { log.info("WorkflowEngineClientRetryEventListener onEvent: {}", event.toPrettyJsonString()); + WorkflowEngineStarterRpcInvokeDTO dto = event.normalizedData(WorkflowEngineStarterRpcInvokeDTO.class); + + Method method = methodCache.getOrDefault(dto.getMethodName(), null); + if (Objects.isNull(method)) { + throw new IllegalStateException("找不到方法:" + dto.getMethodName()); + } + try { + Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), BpmnProcessInstanceCreateDTO.class)); + log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); + } catch (Exception e) { + log.error("Event Invoke Exception: {}", e.getMessage()); + } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java deleted file mode 100644 index f5a2528c6..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/WorkflowEngineServiceFacade.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.axzo.workflow.starter.service; - -import cn.axzo.framework.rocketmq.EventProducer; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.common.exception.CreateProcessInstanceException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.Map; - -/** - * 流程引擎服务的 Starter 对使用方暴露的核心入口 - * - * @author wangli - * @since 2024/5/21 16:53 - */ -public class WorkflowEngineServiceFacade { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineServiceFacade.class); - private final EventProducer workflowEngineClientEventProducer; - private final WorkflowEngineStarterProperties workflowEngineStarterProperties; - - public WorkflowEngineServiceFacade(EventProducer workflowEngineClientEventProducer, - WorkflowEngineStarterProperties workflowEngineStarterProperties) { - this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; - this.workflowEngineStarterProperties = workflowEngineStarterProperties; - } - - /** - * 同步创建流程实例 - *

- * 同步调用方式实现,使用方需要主动关注接口是否调用成功 - * - * @param dto 创建流程实例的参数 - * @return 返回流程实例 ID - * @throws {@link CreateProcessInstanceException} 创建流程实例失败时抛出异常 - */ - public String createProcessInstanceSync(BpmnProcessInstanceCreateDTO dto) { - return null; - } - - /** - * 异步创建流程实例 - *

- * 异步调用方式实现,内部使用 MQ 解耦,使用方如需要获取流程实例编号信息,则通过监听 MQ 消息即可获取 - */ - public void createProcessInstance(BpmnProcessInstanceCreateDTO dto) { -// asynchronousService.createProcessInstance(dto); - } - - public void cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) { - } - - public void abortProcessInstance(BpmnProcessInstanceAbortDTO dto) { - } - - public void batchAbortProcessInstances(List dtos) { - } - - public BpmnProcessInstanceVO getProcessInstanceSync(String processInstanceId) { - return null; - } - - public Map getProcessVariablesSync() { - return null; - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java deleted file mode 100644 index 07fafdcf7..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/AsynchronousService.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.axzo.workflow.starter.service.impl; - -import cn.axzo.workflow.starter.listener.ProcessListener; -import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; - -/** - * 异步调用服务 - *

- * 该类应该被动态代理实现,在调用方法发送 MQ 事件前,判断接口是否被标记 {@code @Management} 注解, - * 如果被标记且没有配置 {@code workflow.engine.client.manageable} 属性,则不允许调用,否则通过 - * {@link RpcInvokeEventProducer} 发送 MQ 事件后,再调用同步服务进行真实的 RPC 调用 - * - * @author wangli - * @since 2024/5/22 10:55 - */ -public interface AsynchronousService extends ProcessListener { - -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java deleted file mode 100644 index c975ec4c3..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/service/impl/SynchronousService.java +++ /dev/null @@ -1,526 +0,0 @@ -package cn.axzo.workflow.starter.service.impl; - -import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi; -import cn.axzo.workflow.client.feign.bpmn.ProcessDefinitionApi; -import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; -import cn.axzo.workflow.client.feign.bpmn.ProcessJobApi; -import cn.axzo.workflow.client.feign.bpmn.ProcessModelApi; -import cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi; -import cn.axzo.workflow.client.feign.bpmn.ProcessVariableApi; -import cn.axzo.workflow.client.feign.manage.ProcessCategoryApi; -import cn.axzo.workflow.client.feign.manage.ProcessConfigApi; -import cn.axzo.workflow.common.enums.BpmnFlowNodeType; -import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; -import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; -import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; -import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; -import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; -import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; -import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; -import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; -import cn.axzo.workflow.common.model.response.category.CategoryItemVO; -import cn.azxo.framework.common.model.CommonResponse; -import com.alibaba.fastjson.JSON; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.util.StopWatch; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Supplier; - -/** - * 同步调用服务 - *

processActivityApi.trigger(triggerId, async), "触发任务失败", triggerId, async); - } - - - public Boolean setAssignee(BpmnActivitySetAssigneeDTO dto) { - return null; - } - - - public BpmPageResult getProcessDefinitionPage(BpmnProcessDefinitionPageDTO dto) { - return null; - } - - - public Boolean updateProcessDefinition(BpmnProcessDefinitionUpdateDTO dto) { - return null; - } - - - public BpmnProcessDefinitionVO getProcessDefinition(String processDefinitionId) { - return null; - } - - - public BpmnProcessDefinitionVO getProcessDefinitionByDeploymentId(String deploymentId) { - return null; - } - - - public BpmnProcessDefinitionVO getActiveProcessDefinitionByKey(String key) { - return null; - } - - - public Boolean getActiveProcessDefinitionByKey(String processDefinitionId, Integer state) { - return null; - } - - - public String getActiveProcessDefinitionId(String tenantId, String category) { - return null; - } - - - public BpmnModelUpdateDTO getActiveProcessDefinitionJsonModel(String modelId, String category, String tenantId) { - return null; - } - - - public Void delete(String deploymentId, Boolean cascade) { - return null; - } - - - public BpmPageResult getAllProcessInstancePage(BpmnProcessInstanceAdminPageReqVO dto) { - return null; - } - - - public BpmPageResult getMyProcessInstancePage(BpmnProcessInstanceMyPageReqVO dto) { - return null; - } - - - public String createProcessInstance(BpmnProcessInstanceCreateDTO dto) { - return null; - } - - - public String createProcessInstanceWith(BpmnProcessInstanceCreateWithFormDTO dto) { - return null; - } - - - public Boolean cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) { - return null; - } - - - public Boolean abortProcessInstance(BpmnProcessInstanceAbortDTO dto) { - return null; - } - - - public BatchOperationResultVO batchAbortProcessInstance(List dtos) { - return null; - } - - - public Boolean carbonCopyProcessInstance(BpmnProcessInstanceCarbonCopyDTO dto) { - return null; - } - - - public BpmnProcessInstanceVO getProcessInstanceVO(BpmnProcessInstanceQueryDTO dto) { - return null; - } - - - public Boolean updateProcessStatus(String processDefinitionId, Integer status) { - return null; - } - - - public ObjectNode processInstanceGraphical(String processInstanceId, @Nullable String tenantId) { - return null; - } - - - public List processInstanceNodeForecast(String processInstanceId, @Nullable String tenantId) { - return null; - } - - - public List processInstanceFilterNodeForecast(String processInstanceId, @Nullable String tenantId, Boolean allNode, @Nullable List nodeDefinitionKeys) { - return null; - } - - - public Map getProcessVariables(String processInstanceId, @Nullable String tenantId) { - return null; - } - - - public List getTenantIds() { - return null; - } - - - public Boolean checkInstanceApprover(BpmnProcessInstanceCheckApproverDTO dto) { - return null; - } - - - public Void executeDeadLetterJobAction(String jobId, String procInstId) { - return null; - } - - - public BpmPageResult page(BpmnModelSearchDTO dto) { - return null; - } - - - public String create(BpmnModelCreateDTO dto) { - return null; - } - - - public BpmnModelDetailVO getById(String processModelId, String tenantId) { - return null; - } - - - public BpmnModelDetailVO getByKey(String processModelKey, String tenantId) { - return null; - } - - - public BpmnModelExtVO getModelExt(String modelId) { - return null; - } - - - public String update(BpmnModelUpdateDTO dto) { - return null; - } - - - public String deployById(String processModelId, String modelTenantId, String operator) { - return null; - } - - - public String deployByKey(String processModelKey, String modelTenantId, String operator) { - return null; - } - - - public Void unDeployById(String processModelId, String tenantId, String operator) { - return null; - } - - - public Void deleteById(String processModelId, String tenantId) { - return null; - } - - - public Void deleteByKey(String processModelKey, String tenantId) { - return null; - } - - - public Void changeStatus(String modelId, Integer status, String operator) { - return null; - } - - - public List getModelCategoryList() { - return null; - } - - - public BpmPageResult getTodoTaskPage(BpmnTaskPageSearchDTO dto) { - return null; - } - - - public BpmPageResult getDoneTaskPage(BpmnTaskPageSearchDTO dto) { - return null; - } - - - public List getTaskListFlatByProcessInstanceId(String processInstanceId, @Nullable String tenantId) { - return null; - } - - - public List getTaskListGroupByProcessInstanceId(String processInstanceId, @Nullable String tenantId) { - return null; - } - - - public List getActiveTasksByProcessInstanceId(String processInstanceId, String tenantId) { - return null; - } - - - public Boolean approveTask(BpmnTaskAuditDTO dto) { - return null; - } - - - public BatchOperationResultVO batchApproveTask(List dtos) { - return null; - } - - - public Boolean rejectTask(BpmnTaskAuditDTO dto) { - return null; - } - - - public BatchOperationResultVO batchRejectTask(List dtos) { - return null; - } - - - public Boolean transferTask(BpmnTaskTransferDTO dto) { - return null; - } - - - public BatchOperationResultVO batchTransferTask(List dtos) { - return null; - } - - - public Boolean commentTask(BpmnTaskCommentDTO dto) { - return null; - } - - - public Void addAttachment(BpmnTaskAttachmentDTO dto) { - return null; - } - - - public Boolean countersignTask(BpmnTaskCountersignDTO dto) { - return null; - } - - - public Boolean remindTask(BpmnTaskRemindDTO dto) { - return null; - } - - - public String createRobotTask(BpmnRobotTaskCreateDTO dto) { - return null; - } - - - public Boolean completeRobotTask(BpmnRobotTaskCompleteDTO dto) { - return null; - } - - - public String findTaskIdByInstanceIdAndPersonId(String processInstanceId, String personId) { - return null; - } - - - public Map findTaskIdByInstanceIdsAndPersonId(List processInstanceIds, String personId, BpmnFlowNodeType... filterTypes) { - return null; - } - - - public Void createVariable(String executionId, RestBpmnProcessVariable restVariable) { - return null; - } - - - public Void updateVariable(String executionId, RestBpmnProcessVariable restVariable) { - return null; - } - - - public Void deleteVariables(String executionId, String variableNames, String scope) { - return null; - } - - - public CategoryItemVO get(Long id) { - return null; - } - - - public List getByIds(List ids) { - return null; - } - - - public List getByValues(List values) { - return null; - } - - - public CategoryItemVO create(CategoryCreateDTO req) { - return null; - } - - - public CategoryItemVO update(CategoryUpdateDTO dto) { - return null; - } - - - public Boolean delete(Long id) { - return null; - } - - - public Boolean updateState(Long id, Boolean state) { - return null; - } - - - public List list(CategorySearchDTO dto) { - return null; - } - - - public BpmPageResult search(CategorySearchDTO dto) { - return null; - } - - - public Boolean createConfig(CategoryConfigCreateDTO dto) { - return null; - } - - - public Boolean deleteConfig(Long id) { - return null; - } - - - public BpmPageResult configSearch(CategoryConfigSearchDTO dto) { - return null; - } - - - public Boolean updateCategoryConfigType(Long id, String configType) { - return null; - } - - - public Boolean checkCategoryStatus(Long tenantId, String categoryCode) { - return null; - } - - - public List getDefaultButtons() { - return null; - } - - private T parseResult(Supplier> supplier, String operationType, Object... args) { - return parseResult(supplier, operationType, null, args); - } - - private T parseResult(Supplier> supplier, String operationType, Consumer> consumer, Object... args) { - log.info("{}-Param: {}", operationType, JSON.toJSONString(args)); - CommonResponse response = printLatency(supplier, operationType); - log.info("{}-Result: {}", operationType, JSON.toJSONString(response)); - if (!Objects.equals(HttpStatus.OK.value(), response.getCode())) { - if (consumer != null) { - consumer.accept(response); - } else { - throw new RuntimeException(response.getMsg()); - } - } - return response.getData(); - } - - public R printLatency(Supplier function, String optType) { - StopWatch stopWatch = new StopWatch(optType); - stopWatch.start(optType); - R r = function.get(); - stopWatch.stop(); - log.info(stopWatch.shortSummary()); - return r; - } -} From d07e580e7b0cacd2c9272240922d44fc0024f156 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 18:39:37 +0800 Subject: [PATCH 034/210] =?UTF-8?q?update(REQ-2516)=20-=20review=20?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/WorkflowEngineStarterAutoConfiguration.java | 7 +++---- .../starter/mq/execute/interceptor/ExecutorInvoker.java | 2 +- .../starter/mq/execute/interceptor/LogInterceptor.java | 2 +- .../starter/mq/execute/interceptor/RetryInterceptor.java | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 37165542d..9cbc0ccbc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -8,7 +8,6 @@ import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; import cn.axzo.workflow.starter.mq.execute.interceptor.LogInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.RetryInterceptor; -import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -39,9 +38,9 @@ public class WorkflowEngineStarterAutoConfiguration { List interceptors = new ArrayList<>(); interceptors.add(new LogInterceptor()); interceptors.add(new RetryInterceptor()); - if (!CollectionUtils.isEmpty(additionalInterceptors)) { - additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); - } +// if (!CollectionUtils.isEmpty(additionalInterceptors)) { +// additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); +// } interceptors.add(new ExecutorInvoker()); return new ListenerExecutorImpl(initInterceptorChain(interceptors)); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java index fadcb9df5..5cd92acee 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java @@ -4,7 +4,7 @@ import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import java.util.function.Consumer; -public class ExecutorInvoker extends AbstractListenerInterceptor { +public final class ExecutorInvoker extends AbstractListenerInterceptor { @Override public void execute(ListenerExecutor executor, Consumer consumer, T t) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java index 7961f0f73..4e4649870 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java @@ -7,7 +7,7 @@ import org.springframework.util.StopWatch; import java.util.function.Consumer; -public class LogInterceptor extends AbstractListenerInterceptor { +public final class LogInterceptor extends AbstractListenerInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class); @Override diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java index 9758b5aaf..65e4d1d54 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java @@ -11,7 +11,7 @@ import java.util.function.Consumer; @Getter @Setter -public class RetryInterceptor extends AbstractListenerInterceptor { +public final class RetryInterceptor extends AbstractListenerInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(RetryInterceptor.class); @@ -39,7 +39,7 @@ public class RetryInterceptor extends AbstractListenerInterceptor { throw new ServiceException(numOfRetries + " retries failed with Exception. Giving up."); } - protected void waitBeforeRetry(long waitTime) { + private void waitBeforeRetry(long waitTime) { try { Thread.sleep(waitTime); } catch (InterruptedException e) { From 953296194b0fb5e4c4f533ff995f44ab4f2a8c51 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 May 2024 19:04:04 +0800 Subject: [PATCH 035/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20RPC=20=E5=8A=A8=E4=BD=9C=20MQ=20=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E7=9B=91=E5=90=AC=E5=99=A8=E7=9A=84=20Bean=20=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/RocketMQConfiguration.java | 2 +- .../WorkflowEngineStarterRetryEventListener.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java index 2ad4b1d6a..197b42e5d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -137,7 +137,7 @@ public class RocketMQConfiguration { } } - @Bean(initMethod = "init") + @Bean public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer, Environment environment, WorkflowCoreService workflowCoreService) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 4b09f8a6c..695cf6564 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -11,6 +11,7 @@ import com.alibaba.fastjson.JSON; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; @@ -26,7 +27,7 @@ import java.util.Objects; * @author wangli * @since 2024/5/21 16:28 */ -public class WorkflowEngineStarterRetryEventListener implements EventHandler { +public class WorkflowEngineStarterRetryEventListener implements EventHandler, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryEventListener.class); private final EventConsumer eventConsumer; private final Environment environment; @@ -70,10 +71,6 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler { return expression; } - public void init() { - eventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); - } - @SneakyThrows @Override public void onEvent(Event event, EventConsumer.Context context) { @@ -82,7 +79,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler { Method method = methodCache.getOrDefault(dto.getMethodName(), null); if (Objects.isNull(method)) { - throw new IllegalStateException("找不到方法:" + dto.getMethodName()); + throw new IllegalStateException("Not found method:" + dto.getMethodName()); } try { Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), BpmnProcessInstanceCreateDTO.class)); @@ -92,4 +89,8 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler { } } + @Override + public void afterPropertiesSet() { + eventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); + } } From c78897392c5c0df62383e652c62c0ee1976f2771 Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 30 May 2024 23:42:27 +0800 Subject: [PATCH 036/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20MQ=20=E6=B6=88=E8=B4=B9=E8=80=85=E5=9C=A8=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E4=B8=8E=E6=9C=8D=E5=8A=A1=E5=99=A8=E4=B9=8B=E9=97=B4?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E8=83=BD=E4=BA=92=E4=B8=8D=E5=BD=B1=E5=93=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/RocketMQConfiguration.java | 4 ++ .../NonContainerEnvironmentCondition.java | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java index 197b42e5d..ca0e6c612 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -7,6 +7,7 @@ import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import org.apache.rocketmq.common.message.MessageExt; @@ -19,6 +20,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @@ -106,6 +108,7 @@ public class RocketMQConfiguration { } @Component + @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${MY_POD_NAMESPACE:debugging}_consumer", consumeMode = ConsumeMode.ORDERLY, @@ -122,6 +125,7 @@ public class RocketMQConfiguration { } @Component + @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java new file mode 100644 index 000000000..622fb40ae --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java @@ -0,0 +1,67 @@ +package cn.axzo.workflow.starter.common.condition; + +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.StringUtils; + +import java.util.Objects; + +/** + * 用于处理 MQ 的消费者, 在本地启动或在容器中启动时, 能自主控制是否并入统一的消费组 + *

+ * 可查看 {@link WorkflowEngineStarterProperties#localConsumer} 属性, 来了解本来的用途, + * 特别需要注意的是: Starter 是结合 K8S 的 命名空间(namespace) 来处理的. 如果公司在删减/变更 + * 环境后,可能会导致 {@link NonContainerEnvironmentCondition#mappingNamespace(String)} + * 方法异常. + * + * @author wangli + * @since 2024/5/30 22:19 + */ +public class NonContainerEnvironmentCondition implements Condition { + + private static final Logger log = LoggerFactory.getLogger(NonContainerEnvironmentCondition.class); + + private static final String MY_POD_NAMESPACE = "MY_POD_NAMESPACE"; + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment(); + // 优先外部化配置 + Boolean localCustomer = environment.getProperty("workflow.engine.starter.local-consumer", Boolean.class); + if (Objects.isNull(localCustomer)) { + // 获取默认值 + localCustomer = new WorkflowEngineStarterProperties().getLocalConsumer(); + } + log.info("workflow engine starter local consumer status: {}", localCustomer); + + String myPodNamespace = environment.getProperty(MY_POD_NAMESPACE); + if (localCustomer && !StringUtils.hasText(myPodNamespace)) { + environment.getSystemProperties().put(MY_POD_NAMESPACE, mappingNamespace(environment.getProperty("spring.profiles.active"))); + } + + return true; + } + + private String mappingNamespace(String namespace) { + switch (namespace) { + case "dev": + case "local": + return "java-dev"; + case "test": + return "test"; + case "pre": + return "pre"; + case "live": + return "live"; + case "master": + return "pro"; + default: + throw new IllegalArgumentException(String.format("namespace %s is not supported", namespace)); + } + } +} From 44d31536c36d5618eac0d72030a4adfdc5645899 Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 30 May 2024 23:42:45 +0800 Subject: [PATCH 037/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/WorkflowEngineStarterProperties.java | 8 +++++++- .../feign/ext/WorkflowEngineStarterInvocationHandler.java | 4 ++-- .../WorkflowEngineStarterInvocationHandlerFactory.java | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 099bd18b8..f6ed6d5d5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -20,11 +20,17 @@ public class WorkflowEngineStarterProperties { /** * 本地启动是否消费容器的广播事件 + *

+ * 默认 false, 本地启动应用时, 将创建消息组名称中含有"debugging"的消费组. + * 否则, 本地启动应用时, 将与容器环境中所有实例共同消费广播事件. */ private Boolean localConsumer = false; /** - * 方法调用默认采用的模式 + * WorkflowCoreService 类中所有方法调用时默认采用的模式 + *

+ * 如果是同步调用,则直接通过普通 FeignClient 进行调用, + * 否则将通过 MQ 将 RPC 调用进行解耦 */ private RpcInvokeModeEnum invokeMode = SYNC; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java index 583b5b96c..b8bc5a5c5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -9,12 +9,12 @@ import java.lang.reflect.Proxy; import java.util.Map; /** - * TODO + * Workflow Engine Starter Core Service Invocation Handler * * @author wangli * @since 2024/5/29 22:58 */ -public class WorkflowEngineStarterInvocationHandler implements InvocationHandler { +class WorkflowEngineStarterInvocationHandler implements InvocationHandler { private final Target target; private final Map dispatch; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java index 028e6d66f..26a133e30 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandlerFactory.java @@ -8,7 +8,7 @@ import java.lang.reflect.Method; import java.util.Map; /** - * TODO + * 用于生成 InvocationHandler * * @author wangli * @since 2024/5/29 22:56 From b333344ab73ac4f9ac74530d0bc424624b713e0e Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 30 May 2024 23:43:11 +0800 Subject: [PATCH 038/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E6=B3=A8=E9=87=8A,=20=E9=81=BF=E5=85=8D=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/broadcast/consumer/InnerActivityEventListener.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index fc3be696d..2983c2859 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -11,7 +11,6 @@ import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.List; @@ -21,7 +20,7 @@ import java.util.function.Consumer; * @author wangli * @since 2024/5/21 15:51 */ -@Component +//@Component public class InnerActivityEventListener implements WorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( From bfe7819565bebb3a812bd8416dc5058b5458ca42 Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 30 May 2024 23:45:43 +0800 Subject: [PATCH 039/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/WorkflowEngineStarterProperties.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index f6ed6d5d5..b14bf5989 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -34,6 +34,10 @@ public class WorkflowEngineStarterProperties { */ private RpcInvokeModeEnum invokeMode = SYNC; + /** + * 该属性还不确定能否实现 + */ + @Deprecated private Boolean autoAck = false; public Boolean getManageable() { From 96e277c85e6341e042724d9ea41beace81c0fa0a Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 31 May 2024 10:23:29 +0800 Subject: [PATCH 040/210] =?UTF-8?q?update=20-=20REQ-2516-=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E6=8E=A5=E5=8F=A3=E7=BB=A7=E6=89=BForder=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=A2=9E=E5=8A=A0=E6=8E=92=E5=BA=8F=EF=BC=8C=E8=B0=83?= =?UTF-8?q?=E6=95=B4Listener=E7=94=9F=E6=88=90bean=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/RocketMQConfiguration.java | 13 +++++++++-- .../listener/MessageNotificationListener.java | 3 ++- .../listener/ProcessActivityListener.java | 15 +++++-------- .../listener/ProcessInstanceListener.java | 4 +++- .../starter/listener/ProcessListener.java | 4 +++- .../starter/listener/ProcessTaskListener.java | 4 +++- .../consumer/InnerActivityEventListener.java | 4 +++- .../consumer/InnerNoticeEventListener.java | 5 +++++ .../WorkflowEngineBroadcastEventListener.java | 22 +++++++------------ 9 files changed, 44 insertions(+), 30 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java index 2ad4b1d6a..1d6430fbd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java @@ -7,6 +7,8 @@ import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import org.apache.rocketmq.common.message.MessageExt; @@ -16,6 +18,7 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; @@ -25,6 +28,7 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.HashMap; +import java.util.List; import java.util.Objects; import java.util.function.Consumer; @@ -111,7 +115,7 @@ public class RocketMQConfiguration { consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) - public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { @Resource private EventConsumer eventConsumer; @@ -127,7 +131,7 @@ public class RocketMQConfiguration { consumeMode = ConsumeMode.CONCURRENTLY, nameServer = "${rocketmq.name-server}" ) - public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { + public static class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { @Resource private EventConsumer eventConsumer; @@ -144,4 +148,9 @@ public class RocketMQConfiguration { return new WorkflowEngineStarterRetryEventListener(eventConsumer, environment, workflowCoreService); } + @Bean(initMethod = "init") + public WorkflowEngineBroadcastEventListener WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, ObjectProvider> listeners) { + return new WorkflowEngineBroadcastEventListener(eventConsumer, listeners.getIfAvailable()); + } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java index d3ea96dfc..23a92d09d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.listener; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; +import org.springframework.core.Ordered; /** * TODO @@ -8,7 +9,7 @@ import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; * @author wangli * @since 2024/5/27 16:25 */ -public interface MessageNotificationListener { +public interface MessageNotificationListener extends Ordered { void pushNotice(MessagePushDTO messagePushDTO); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java index 78d55f7d9..f4c9f77a3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java @@ -1,42 +1,39 @@ package cn.axzo.workflow.starter.listener; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; +import org.springframework.core.Ordered; /** * @author wangli * @since 2024/5/27 16:25 */ -public interface ProcessActivityListener { +public interface ProcessActivityListener extends Ordered { /** * 节点已启动 * * @param activityDTO 入参 */ - default void onStart(ProcessActivityDTO activityDTO) { - } + void onStart(ProcessActivityDTO activityDTO); /** * 节点等待业务指定审批人 * * @param activityDTO 入参 */ - default void onWaitAssignee(ProcessActivityDTO activityDTO) { - } + void onWaitAssignee(ProcessActivityDTO activityDTO); /** * 节点已完成 * * @param activityDTO 入参 */ - default void onTake(ProcessActivityDTO activityDTO) { - } + void onTake(ProcessActivityDTO activityDTO); /** * 节点已取消 * * @param activityDTO 入参 */ - default void onEnd(ProcessActivityDTO activityDTO) { - } + void onEnd(ProcessActivityDTO activityDTO); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java index 4643d4e0a..c4f5112bd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java @@ -1,12 +1,14 @@ package cn.axzo.workflow.starter.listener; +import org.springframework.core.Ordered; + /** * TODO * * @author wangli * @since 2024/5/27 16:20 */ -public interface ProcessInstanceListener extends ProcessListener { +public interface ProcessInstanceListener extends Ordered { void created(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java index 71ddc7706..92aaa9c83 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java @@ -1,12 +1,14 @@ package cn.axzo.workflow.starter.listener; +import org.springframework.core.Ordered; + /** * TODO * * @author wangli * @since 2024/5/27 16:26 */ -public interface ProcessListener { +public interface ProcessListener extends Ordered { /** * 入参来源于配置 * diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java index 54754c930..f3d956326 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java @@ -1,10 +1,12 @@ package cn.axzo.workflow.starter.listener; +import org.springframework.core.Ordered; + /** * TODO * * @author wangli * @since 2024/5/27 16:21 */ -public interface ProcessTaskListener { +public interface ProcessTaskListener extends Ordered { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index fc3be696d..7973fd8e7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -10,6 +10,7 @@ import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -32,13 +33,14 @@ public class InnerActivityEventListener implements WorkflowListener { ); @Autowired - private List activityListeners; + private ObjectProvider> activityListenersProvider; @Autowired private ListenerExecutor listenerExecutor; @Override public void handEvent(Event event, EventConsumer.Context context) { + List activityListeners = activityListenersProvider.getIfAvailable(); if (!CollectionUtils.isEmpty(activityListeners)) { ProcessActivityDTO activityDTO = JSON.parseObject(event.getData().toString(), ProcessActivityDTO.class); ProcessActivityEventEnum type = activityDTO.getType(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java index 1508fed01..76233d96a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java @@ -30,6 +30,11 @@ public class InnerNoticeEventListener { public static void main(String[] args) { MessageNotificationListener listener = new MessageNotificationListener() { + @Override + public int getOrder() { + return 0; + } + @Override public void pushNotice(MessagePushDTO messagePushDTO) { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 8c5741f5e..feecf0ba1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -7,24 +7,26 @@ import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.stereotype.Component; import java.util.List; import java.util.Objects; /** - * TODO - * * @author wangli * @since 2024/5/21 15:50 */ -@Component -public class WorkflowEngineBroadcastEventListener implements EventHandler, InitializingBean { +public class WorkflowEngineBroadcastEventListener implements EventHandler { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastEventListener.class); private final EventConsumer eventConsumer; private final List workflowListeners; + public void init() { + eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); + } + public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, List workflowListeners) { this.eventConsumer = eventConsumer; this.workflowListeners = workflowListeners; @@ -43,12 +45,4 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi } } } - - @Override - public void afterPropertiesSet() throws Exception { - eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); - } } From a347cc45fe15c23a1cb1a0014c031ad9f10fab4b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 31 May 2024 14:25:36 +0800 Subject: [PATCH 041/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E6=B5=8B=E8=AF=95=E6=95=B4=E4=B8=AA=20RPC=20=E5=90=8C?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E6=A8=A1=E5=BC=8F=EF=BC=8C=E4=B8=94=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=80=9A=E8=BF=87=20Properties=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=BB=98=E8=AE=A4=E5=90=8C=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/WorkflowEngineEventEnum.java | 2 +- .../server/controller/web/TestController.java | 13 ++- ...orkflowEngineStarterAutoConfiguration.java | 2 +- .../WorkflowEngineStarterProperties.java | 4 +- ...owEngineStarterRocketMQConfiguration.java} | 97 ++++++++++++------- .../starter/common/util/ThreadUtil.java | 4 + .../feign/ext/ComplexInvokeClient.java | 69 +++++++++++-- ...rkflowEngineStarterRetryEventListener.java | 13 ++- 8 files changed, 151 insertions(+), 53 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{RocketMQConfiguration.java => WorkflowEngineStarterRocketMQConfiguration.java} (69%) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java index a74dcd261..b03fb9847 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/WorkflowEngineEventEnum.java @@ -39,7 +39,7 @@ public enum WorkflowEngineEventEnum { } public String getTag() { - return tag; + return eventCode.getName(); } public String getDesc() { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index a6cc9eafc..96dc07b76 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -131,13 +131,20 @@ public class TestController { } @GetMapping("/test5") - public CommonResponse test5() { + public CommonResponse test5(@RequestParam(required = false) Boolean sync) { BpmnProcessInstanceCreateDTO dto = new BpmnProcessInstanceCreateDTO(); dto.setProcessDefinitionKey("1"); dto.setCooperationOrg(new CooperationOrgDTO()); dto.setBusinessKey("businessKey"); dto.setInitiator(new BpmnTaskDelegateAssigner()); - workflowCoreService.async().createProcessInstance(dto); - return CommonResponse.success(true); + if (Objects.nonNull(sync)) { + if (sync) { + workflowCoreService.sync(); + } else { + workflowCoreService.async(); + } + } + CommonResponse processInstance = workflowCoreService.createProcessInstance(dto); + return processInstance; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 9cbc0ccbc..dc966c518 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -28,7 +28,7 @@ import java.util.List; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) @EnableFeignClients(clients = {WorkflowCoreService.class}) -@Import(RocketMQConfiguration.class) +@Import(WorkflowEngineStarterRocketMQConfiguration.class) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index b14bf5989..e0bb3db3c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -3,7 +3,7 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; -import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; +import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; /** * Workflow Engine Starter Properties @@ -32,7 +32,7 @@ public class WorkflowEngineStarterProperties { * 如果是同步调用,则直接通过普通 FeignClient 进行调用, * 否则将通过 MQ 将 RPC 调用进行解耦 */ - private RpcInvokeModeEnum invokeMode = SYNC; + private RpcInvokeModeEnum invokeMode = ASYNC; /** * 该属性还不确定能否实现 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java similarity index 69% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index ca0e6c612..5eda00fbf 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/RocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.starter; import cn.axzo.framework.rocketmq.BaseListener; import cn.axzo.framework.rocketmq.DefaultEventConsumer; +import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; @@ -17,8 +18,9 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -37,8 +39,8 @@ import java.util.function.Consumer; * @since 2024/5/30 14:05 */ @Configuration(proxyBeanMethods = false) -public class RocketMQConfiguration { - private final Logger log = LoggerFactory.getLogger(RocketMQConfiguration.class); +public class WorkflowEngineStarterRocketMQConfiguration { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRocketMQConfiguration.class); private static final String DEFAULT_MODULE = "workflowEngine"; private static final String DEFAULT_EVENT = "topic_workflow_engine_"; @@ -48,6 +50,50 @@ public class RocketMQConfiguration { @Value("${spring.profiles.active:dev}") private String activeProfile; + //================================= Workflow Engine Broadcast MQ =================================// + @Bean + @ConditionalOnMissingBean(EventHandlerRepository.class) + public EventHandlerRepository eventHandlerRepository() { + return new EventHandlerRepository((ex, logText) -> { + log.warn("MQ, handle warning {}", logText, ex); + if (Objects.nonNull(ex)) { + throw new RuntimeException(ex); + } + }); + } + + @Bean + @ConditionalOnMissingBean(EventProducer.class) + public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { + Consumer callback = eventWrapper -> { + if (eventWrapper.isHandled()) { + // 只收集被App真正消费的消息. + //String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY); + } + }; + return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); + } + + @Component + @Conditional(NonContainerEnvironmentCondition.class) + @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", + consumerGroup = "GID_${spring.application.name}_workflow_engine_${MY_POD_NAMESPACE:debugging}_consumer", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + @Resource(name = "eventConsumer") + private EventConsumer eventConsumer; + + @Override + public void onMessage(MessageExt message) { + super.onEvent(message, eventConsumer); + } + } + + + //======================================= RPC Invoke MQ ========================================// + /** * 客户端 RPC Retry 事件生产者 * @@ -58,7 +104,7 @@ public class RocketMQConfiguration { public EventProducer workflowEngineClientEventProducer(RocketMQTemplate rocketMQTemplate) { return new RocketMQEventProducer(rocketMQTemplate, DEFAULT_MODULE, - applicationName, + applicationName + "Starter", EventProducer.Context.builder() .meta(RocketMQEventProducer.RocketMQMessageMeta.builder() .topic(DEFAULT_EVENT + activeProfile) @@ -79,14 +125,14 @@ public class RocketMQConfiguration { } @Bean - public RpcInvokeEventProducer rpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer, + public RpcInvokeEventProducer rpcInvokeEventProducer(@Qualifier("workflowEngineClientEventProducer") EventProducer workflowEngineClientEventProducer, Environment environment) { return new RpcInvokeEventProducer(workflowEngineClientEventProducer, environment); } @Bean - @ConditionalOnClass(EventHandlerRepository.class) - public EventHandlerRepository eventHandlerRepository() { + @ConditionalOnMissingBean(name = "workflowEngineStarterEventHandlerRepository") + public EventHandlerRepository workflowEngineStarterEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { log.warn("MQ, handle warning {}", logText, ex); if (Objects.nonNull(ex)) { @@ -96,32 +142,16 @@ public class RocketMQConfiguration { } @Bean - @ConditionalOnClass(EventConsumer.class) - public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { + @ConditionalOnMissingBean(name = "workflowEngineStarterEventConsumer") + public EventConsumer workflowEngineStarterEventConsumer(@Qualifier("workflowEngineStarterEventHandlerRepository") EventHandlerRepository workflowEngineStarterEventHandlerRepository) { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. - //String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY); + Event event = eventWrapper.getEvent(); + log.info("MQ, handled event: {}", event.toPrettyJsonString()); } }; - return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); - } - - @Component - @Conditional(NonContainerEnvironmentCondition.class) - @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_${MY_POD_NAMESPACE:debugging}_consumer", - consumeMode = ConsumeMode.ORDERLY, - nameServer = "${rocketmq.name-server}" - ) - public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { - @Resource - private EventConsumer eventConsumer; - - @Override - public void onMessage(MessageExt message) { - super.onEvent(message, eventConsumer); - } + return new DefaultEventConsumer(applicationName + "Starter", workflowEngineStarterEventHandlerRepository, callback); } @Component @@ -129,23 +159,24 @@ public class RocketMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, + replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { - @Resource - private EventConsumer eventConsumer; + @Resource(name = "workflowEngineStarterEventConsumer") + private EventConsumer workflowEngineStarterEventConsumer; @Override public void onMessage(MessageExt message) { - super.onEvent(message, eventConsumer); + super.onEvent(message, workflowEngineStarterEventConsumer); } } @Bean - public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(EventConsumer eventConsumer, + public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier("workflowEngineStarterEventConsumer") EventConsumer workflowEngineStarterEventConsumer, Environment environment, WorkflowCoreService workflowCoreService) { - return new WorkflowEngineStarterRetryEventListener(eventConsumer, environment, workflowCoreService); + return new WorkflowEngineStarterRetryEventListener(workflowEngineStarterEventConsumer, environment, workflowCoreService); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java index bccb06b78..59acedc08 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java @@ -19,4 +19,8 @@ public class ThreadUtil { public static RpcInvokeModeEnum get() { return threadLocal.get(); } + + public static void clear() { + threadLocal.remove(); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index a8d375314..d5b72a718 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -6,6 +6,8 @@ import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; +import cn.azxo.framework.common.model.CommonResponse; +import com.alibaba.fastjson.JSON; import feign.Client; import feign.Request; import feign.Response; @@ -13,7 +15,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; @@ -52,21 +59,43 @@ public class ComplexInvokeClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { - log.info("ComplexInvokeClient execute"); + log.info("ComplexInvokeClient execute..."); RpcInvokeModeEnum currentInvokeModeEnum = ThreadUtil.get(); if (Objects.isNull(currentInvokeModeEnum)) { + log.info("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in StarterProperties will be loaded."); currentInvokeModeEnum = getDefaultInvokeMode(request); } + log.info("final InvokeMode : {}", currentInvokeModeEnum); if (Objects.equals(SYNC, currentInvokeModeEnum)) { + log.info("[sync] invoke..."); + ThreadUtil.clear(); return feignClient.execute(request, options); } Map> headers = request.headers(); headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); - // TODO 发送 RPC 调用动作的 MQ 事件 + asyncInvoke(request); + + + return Response.builder() + .status(HttpStatus.OK.value()) + .reason(HttpStatus.OK.getReasonPhrase()) + .headers(headers) + .request(request) + .body(body) + .build(); + } + + /** + * 发送 RPC 调用动作的 MQ 事件 + * + * @param request + */ + private void asyncInvoke(Request request) { + log.info("[async] invoke..."); WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); event.setClassName(request.requestTemplate().feignTarget().type().getName()); event.setMethodName(request.requestTemplate().methodMetadata().method().getName()); @@ -78,12 +107,6 @@ public class ComplexInvokeClient implements Client { event.setOriginUrl(request.url()); event.setBody(new String(request.body(), StandardCharsets.UTF_8)); rpcInvokeEventProducer.send(WORKFLOW_ENGINE_STARTER, event); - - return Response.builder() - .status(HttpStatus.OK.value()) - .body(new byte[0]) - .request(request) - .build(); } private RpcInvokeModeEnum getDefaultInvokeMode(Request request) { @@ -96,4 +119,34 @@ public class ComplexInvokeClient implements Client { } return RpcInvokeModeEnum.valueOf(invokeModel.iterator().next()); } + + static Response.Body body = new Response.Body() { + final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success("Send MQ Success")) + .getBytes(StandardCharsets.UTF_8)); + + @Override + public Integer length() { + return null; + } + + @Override + public boolean isRepeatable() { + return false; + } + + @Override + public InputStream asInputStream() throws IOException { + return inputStream; + } + + @Override + public Reader asReader(Charset charset) throws IOException { + return new InputStreamReader(asInputStream(), charset); + } + + @Override + public void close() throws IOException { + inputStream.close(); + } + }; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 695cf6564..a3643747d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -29,14 +29,16 @@ import java.util.Objects; */ public class WorkflowEngineStarterRetryEventListener implements EventHandler, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryEventListener.class); - private final EventConsumer eventConsumer; + private final EventConsumer workflowEngineStarterEventConsumer; private final Environment environment; private final String currentApplicationName; private final WorkflowCoreService workflowCoreService; private final Map methodCache = new HashMap<>(); - public WorkflowEngineStarterRetryEventListener(EventConsumer eventConsumer, Environment environment, WorkflowCoreService workflowCoreService) { - this.eventConsumer = eventConsumer; + public WorkflowEngineStarterRetryEventListener(EventConsumer workflowEngineStarterEventConsumer, + Environment environment, + WorkflowCoreService workflowCoreService) { + this.workflowEngineStarterEventConsumer = workflowEngineStarterEventConsumer; this.environment = environment; this.currentApplicationName = environment.getProperty("spring.application.name"); this.workflowCoreService = workflowCoreService; @@ -82,15 +84,16 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In throw new IllegalStateException("Not found method:" + dto.getMethodName()); } try { + workflowCoreService.sync(); Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), BpmnProcessInstanceCreateDTO.class)); log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); } catch (Exception e) { - log.error("Event Invoke Exception: {}", e.getMessage()); + log.error("Event Invoke Exception: {}", e.getMessage(), e); } } @Override public void afterPropertiesSet() { - eventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); + workflowEngineStarterEventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); } } From 504f26239fe34494841ba3b06bbc11868cb269fd Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 31 May 2024 14:27:22 +0800 Subject: [PATCH 042/210] =?UTF-8?q?update=20-=20REQ-2516-=E6=89=A7?= =?UTF-8?q?=E8=A1=8CListener=E5=A2=9E=E5=8A=A0=E5=BC=82=E5=B8=B8=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 26 +++++- .../WorkflowEngineStarterProperties.java | 56 +++++++++++++ .../common/enums/FailHandleTypeEnum.java | 23 ++++++ .../WorkflowListenerExeException.java | 41 ++++++++++ .../listener/ProcessInstanceListener.java | 46 +++++++++-- .../consumer/InnerActivityEventListener.java | 3 +- .../consumer/InnerInstanceEventListener.java | 80 ++++++++++++++++--- .../WorkflowEngineBroadcastEventListener.java | 5 ++ .../interceptor/FailBackInterceptor.java | 20 +++++ .../interceptor/FailFastInterceptor.java | 25 ++++++ ...erceptor.java => FailOverInterceptor.java} | 30 ++++--- 11 files changed, 326 insertions(+), 29 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/FailHandleTypeEnum.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/{RetryInterceptor.java => FailOverInterceptor.java} (62%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 9cbc0ccbc..97976a8de 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -4,10 +4,13 @@ import cn.axzo.framework.domain.ServiceException; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import cn.axzo.workflow.starter.mq.execute.ListenerExecutorImpl; +import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; +import cn.axzo.workflow.starter.mq.execute.interceptor.FailBackInterceptor; +import cn.axzo.workflow.starter.mq.execute.interceptor.FailFastInterceptor; +import cn.axzo.workflow.starter.mq.execute.interceptor.FailOverInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.LogInterceptor; -import cn.axzo.workflow.starter.mq.execute.interceptor.RetryInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -34,10 +37,12 @@ public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); @Bean - public ListenerExecutor initListenerExecutor(List additionalInterceptors) { + public ListenerExecutor initListenerExecutor(WorkflowEngineStarterProperties starterProperties, + List additionalInterceptors) { + FailHandleTypeEnum failHandleType = starterProperties.getFailHandleType(); List interceptors = new ArrayList<>(); interceptors.add(new LogInterceptor()); - interceptors.add(new RetryInterceptor()); + interceptors.add(getFailInterceptor(starterProperties, failHandleType)); // if (!CollectionUtils.isEmpty(additionalInterceptors)) { // additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); // } @@ -45,6 +50,21 @@ public class WorkflowEngineStarterAutoConfiguration { return new ListenerExecutorImpl(initInterceptorChain(interceptors)); } + private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties, + FailHandleTypeEnum failHandleType) { + if (failHandleType != null) { + switch (failHandleType) { + case FAIL_BACK: + return new FailBackInterceptor(); + case FAIL_FAST: + return new FailFastInterceptor(); + case FAIL_OVER: + return new FailOverInterceptor(starterProperties.getNumOfRetries(), starterProperties.getWaitTimeInMs(), starterProperties.getWaitIncreaseFactor()); + } + } + return new FailOverInterceptor(starterProperties.getNumOfRetries(), starterProperties.getWaitTimeInMs(), starterProperties.getWaitIncreaseFactor()); + } + public ExecuteInterceptor initInterceptorChain(List chain) { if (chain == null || chain.isEmpty()) { throw new ServiceException("invalid command interceptor chain configuration: " + chain); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index b14bf5989..617028cc7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter; +import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -34,6 +35,29 @@ public class WorkflowEngineStarterProperties { */ private RpcInvokeModeEnum invokeMode = SYNC; + /** + * 失败处理策略: + * 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略) + * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行 + * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 + */ + private FailHandleTypeEnum failHandleType = FailHandleTypeEnum.FAIL_OVER; + + /** + * 自动重试次数 + */ + private int numOfRetries = 3; + + /** + * 初始等待时间,单位:毫秒 + */ + private int waitTimeInMs = 50; + + /** + * 重试累乘因子 + */ + private int waitIncreaseFactor = 3; + /** * 该属性还不确定能否实现 */ @@ -71,4 +95,36 @@ public class WorkflowEngineStarterProperties { public void setAutoAck(Boolean autoAck) { this.autoAck = autoAck; } + + public FailHandleTypeEnum getFailHandleType() { + return failHandleType; + } + + public void setFailHandleType(FailHandleTypeEnum failHandleType) { + this.failHandleType = failHandleType; + } + + public int getNumOfRetries() { + return numOfRetries; + } + + public void setNumOfRetries(int numOfRetries) { + this.numOfRetries = numOfRetries; + } + + public int getWaitTimeInMs() { + return waitTimeInMs; + } + + public void setWaitTimeInMs(int waitTimeInMs) { + this.waitTimeInMs = waitTimeInMs; + } + + public int getWaitIncreaseFactor() { + return waitIncreaseFactor; + } + + public void setWaitIncreaseFactor(int waitIncreaseFactor) { + this.waitIncreaseFactor = waitIncreaseFactor; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/FailHandleTypeEnum.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/FailHandleTypeEnum.java new file mode 100644 index 000000000..0f6d64e32 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/FailHandleTypeEnum.java @@ -0,0 +1,23 @@ +package cn.axzo.workflow.starter.common.enums; + + +import lombok.Getter; + +/** + * 异常处理策略,执行客户端自定义Listener异常处理策略,默认未FAIL_OVER + */ +@Getter +public enum FailHandleTypeEnum { + FAIL_OVER("fail_over", "当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常"), + FAIL_FAST("fail_fast", "快速失败,出错直接抛出异常,listener不再往下执行"), + FAIL_BACK("fail_back", "失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持"), + ; + private final String code; + private final String description; + + FailHandleTypeEnum(String code, String description) { + this.code = code; + this.description = description; + } + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java new file mode 100644 index 000000000..5c6ec1fcc --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java @@ -0,0 +1,41 @@ +package cn.axzo.workflow.starter.common.exception; + +public class WorkflowListenerExeException extends RuntimeException { + private int code; + + public WorkflowListenerExeException(String message) { + super(message); + } + + public WorkflowListenerExeException() { + super(); + } + + public WorkflowListenerExeException(String message, Throwable cause) { + super(message, cause); + } + + public WorkflowListenerExeException(Throwable cause) { + super(cause); + } + + public WorkflowListenerExeException(int code) { + super(); + this.code = code; + } + + public WorkflowListenerExeException(int code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public WorkflowListenerExeException(int code, String message) { + super(message); + this.code = code; + } + + public WorkflowListenerExeException(int code, Throwable cause) { + super(cause); + this.code = code; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java index c4f5112bd..145f422d9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java @@ -1,19 +1,55 @@ package cn.axzo.workflow.starter.listener; +import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import org.springframework.core.Ordered; /** - * TODO - * * @author wangli * @since 2024/5/27 16:20 */ public interface ProcessInstanceListener extends Ordered { - void created(); + /** + * 流程实例创建成功后回调 + * + * @param processInstanceDTO + */ + void onCreated(ProcessInstanceDTO processInstanceDTO); - void completed(); + /** + * 流程实例开始运行后回调 + * + * @param processInstanceDTO + */ + void onStarted(ProcessInstanceDTO processInstanceDTO); - void deleted(); + /** + * 流程实例被撤回后回调 + * + * @param processInstanceDTO + */ + void onCancelled(ProcessInstanceDTO processInstanceDTO); + /** + * 流程实例被驳回后回调 + * + * @param processInstanceDTO + */ + void onRejected(ProcessInstanceDTO processInstanceDTO); + + /** + * 流程实例被中止后回调 + * + * @param event + */ + void onAborted(ProcessInstanceDTO event); + + /** + * 流程实例运行完成后回调 + *

+ * 注意: 完成只是说明流程实例已停止运行 + * + * @param event + */ + void onCompleted(ProcessInstanceDTO event); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index d0a6ec2ea..7973fd8e7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -12,6 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.List; @@ -21,7 +22,7 @@ import java.util.function.Consumer; * @author wangli * @since 2024/5/21 15:51 */ -//@Component +@Component public class InnerActivityEventListener implements WorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index 4caf3b922..8cfd748eb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -1,27 +1,89 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; +import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; +import cn.axzo.workflow.starter.listener.ProcessInstanceListener; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.List; +import java.util.function.Consumer; + +import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_ABORTED; +import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_CANCELLED; +import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_COMPLETED; +import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_CREATED; +import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_REJECTED; +import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_STARTED; /** - * TODO - * * @author wangli * @since 2024/5/21 15:51 */ -public class InnerInstanceEventListener { +@Component +public class InnerInstanceEventListener implements WorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( - ProcessInstanceEventEnum.PROCESS_INSTANCE_CREATED.getEventCode(), - ProcessInstanceEventEnum.PROCESS_INSTANCE_STARTED.getEventCode(), - ProcessInstanceEventEnum.PROCESS_INSTANCE_CANCELLED.getEventCode(), - ProcessInstanceEventEnum.PROCESS_INSTANCE_REJECTED.getEventCode(), - ProcessInstanceEventEnum.PROCESS_INSTANCE_ABORTED.getEventCode(), - ProcessInstanceEventEnum.PROCESS_INSTANCE_COMPLETED.getEventCode() + PROCESS_INSTANCE_CREATED.getEventCode(), + PROCESS_INSTANCE_STARTED.getEventCode(), + PROCESS_INSTANCE_CANCELLED.getEventCode(), + PROCESS_INSTANCE_REJECTED.getEventCode(), + PROCESS_INSTANCE_ABORTED.getEventCode(), + PROCESS_INSTANCE_COMPLETED.getEventCode() ); + + @Autowired + private ObjectProvider> activityListenersProvider; + + @Autowired + private ListenerExecutor listenerExecutor; + + @Override + public void handEvent(Event event, EventConsumer.Context context) { + List instanceListeners = activityListenersProvider.getIfAvailable(); + if (!CollectionUtils.isEmpty(instanceListeners)) { + ProcessInstanceDTO instanceDTO = JSON.parseObject(event.getData().toString(), ProcessInstanceDTO.class); + ProcessInstanceEventEnum type = instanceDTO.getType(); + for (ProcessInstanceListener instanceListener : instanceListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_INSTANCE_CREATED: + consumer = instanceListener::onCreated; + break; + case PROCESS_INSTANCE_STARTED: + consumer = instanceListener::onStarted; + break; + case PROCESS_INSTANCE_CANCELLED: + consumer = instanceListener::onCancelled; + break; + case PROCESS_INSTANCE_ABORTED: + consumer = instanceListener::onAborted; + break; + case PROCESS_INSTANCE_COMPLETED: + consumer = instanceListener::onCompleted; + break; + case PROCESS_INSTANCE_REJECTED: + consumer = instanceListener::onRejected; + break; + default: + log.warn("unknown process activity event type: {}", type); + } + listenerExecutor.execute(consumer, instanceDTO); + } + } + } + + @Override + public boolean support(Event event) { + return event != null && SUPPORTED_EVENT_CODES.contains(event.getEventCode()); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index feecf0ba1..f1c4956c9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; import java.util.List; import java.util.Objects; @@ -39,6 +40,10 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler { log.warn("AllMessagePushEventHandler MessagePushDTO is null"); return; } + if (CollectionUtils.isEmpty(workflowListeners)) { + log.warn("AllWorkflowListener is null,msg:{}", JSON.toJSONString(event)); + return; + } for (WorkflowListener workflowListener : workflowListeners) { if (workflowListener.support(event)) { workflowListener.handEvent(event, context); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java new file mode 100644 index 000000000..fca7356d0 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java @@ -0,0 +1,20 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; + +import java.util.function.Consumer; + +/** + * 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 + */ +public final class FailBackInterceptor extends AbstractListenerInterceptor { + @Override + public void execute(ListenerExecutor executor, Consumer consumer, T t) { + throw new UnsupportedOperationException("FailBackInterceptor"); + } + + @Override + public void setNext(ExecuteInterceptor next) { + throw new UnsupportedOperationException("FailBackInterceptor"); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java new file mode 100644 index 000000000..657898731 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.starter.mq.execute.interceptor; + +import cn.axzo.workflow.starter.common.exception.WorkflowListenerExeException; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; + +import java.util.function.Consumer; + +/** + * 快速失败,出错直接抛出异常,listener不再往下执行 + */ +public final class FailFastInterceptor extends AbstractListenerInterceptor { + + @Override + public void execute(ListenerExecutor executor, Consumer consumer, T t) { + try { + getNext().execute(executor, consumer, t); + } catch (Exception e) { + throw new WorkflowListenerExeException( + "Failed to invoke the method " +// + methodName + + ". Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); + } + } + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailOverInterceptor.java similarity index 62% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailOverInterceptor.java index 65e4d1d54..bd130890b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/RetryInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailOverInterceptor.java @@ -1,23 +1,30 @@ package cn.axzo.workflow.starter.mq.execute.interceptor; -import cn.axzo.framework.domain.ServiceException; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import lombok.Getter; -import lombok.Setter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.function.Consumer; -@Getter -@Setter -public final class RetryInterceptor extends AbstractListenerInterceptor { +/** + * 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常 + */ +public final class FailOverInterceptor extends AbstractListenerInterceptor { - private static final Logger LOGGER = LoggerFactory.getLogger(RetryInterceptor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FailOverInterceptor.class); - protected int numOfRetries = 3; - protected int waitTimeInMs = 50; - protected int waitIncreaseFactor = 5; + private int numOfRetries = 3; + private int waitTimeInMs = 50; + private int waitIncreaseFactor = 5; + + public FailOverInterceptor() { + } + + public FailOverInterceptor(int numOfRetries, int waitTimeInMs, int waitIncreaseFactor) { + this.numOfRetries = numOfRetries; + this.waitTimeInMs = waitTimeInMs; + this.waitIncreaseFactor = waitIncreaseFactor; + } @Override public void execute(ListenerExecutor executor, Consumer consumer, T t) { @@ -31,12 +38,13 @@ public final class RetryInterceptor extends AbstractListenerInterceptor { } try { getNext().execute(executor, consumer, t); + return; } catch (Exception e) { LOGGER.info("Caught exception: {}", e.getMessage(), e); } failedAttempts++; } while (failedAttempts <= numOfRetries); - throw new ServiceException(numOfRetries + " retries failed with Exception. Giving up."); +// throw new ServiceException(numOfRetries + " retries failed with Exception. Giving up."); } private void waitBeforeRetry(long waitTime) { From d934bd42dfff63e53d1343fb02235c8808d570b4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 31 May 2024 14:40:22 +0800 Subject: [PATCH 043/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=20MQ=20=E7=9A=84=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...flowEngineStarterRocketMQConfiguration.java | 17 ++++++++++++----- .../WorkflowEngineBroadcastEventListener.java | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index aae8fff50..949794a62 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -8,9 +8,9 @@ import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; -import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import org.apache.rocketmq.common.message.MessageExt; @@ -72,7 +72,8 @@ public class WorkflowEngineStarterRocketMQConfiguration { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. - //String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY); + Event event = eventWrapper.getEvent(); + log.info("WorkflowEngine Broadcast MQ, handled event: {}", event.toPrettyJsonString()); } }; return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); @@ -85,7 +86,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) - public class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { @Resource(name = "eventConsumer") private EventConsumer eventConsumer; @@ -95,6 +96,12 @@ public class WorkflowEngineStarterRocketMQConfiguration { } } + @Bean + public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, + ObjectProvider> listeners) { + return new WorkflowEngineBroadcastEventListener(eventConsumer, listeners.getIfAvailable()); + } + //======================================= RPC Invoke MQ ========================================// @@ -152,7 +159,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. Event event = eventWrapper.getEvent(); - log.info("MQ, handled event: {}", event.toPrettyJsonString()); + log.info("WorkflowEngineStarter RPC MQ, handled event: {}", event.toPrettyJsonString()); } }; return new DefaultEventConsumer(applicationName + "Starter", workflowEngineStarterEventHandlerRepository, callback); @@ -166,7 +173,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) - public class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { + public static class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { @Resource(name = "workflowEngineStarterEventConsumer") private EventConsumer workflowEngineStarterEventConsumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index f1c4956c9..59fa2012d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.util.CollectionUtils; import java.util.List; @@ -16,18 +17,11 @@ import java.util.Objects; * @author wangli * @since 2024/5/21 15:50 */ -public class WorkflowEngineBroadcastEventListener implements EventHandler { +public class WorkflowEngineBroadcastEventListener implements EventHandler, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastEventListener.class); private final EventConsumer eventConsumer; private final List workflowListeners; - public void init() { - eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); - } - public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, List workflowListeners) { this.eventConsumer = eventConsumer; this.workflowListeners = workflowListeners; @@ -50,4 +44,12 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler { } } } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); + } } From 3cfb68470ff102fba4667bc05c35920c01280b39 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 31 May 2024 16:48:57 +0800 Subject: [PATCH 044/210] =?UTF-8?q?update=20-=20REQ-2516-=E6=8C=89?= =?UTF-8?q?=E7=85=A7=E9=A1=BA=E5=BA=8F=E6=89=A7=E8=A1=8C=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E8=87=AA=E5=AE=9A=E4=B9=89listener?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/MessageNotificationListener.java | 39 +++++++++++- .../starter/listener/ProcessTaskListener.java | 27 ++++++++- .../consumer/AbstractWorkflowListener.java | 33 +++++++++++ .../consumer/InnerActivityEventListener.java | 15 +---- .../consumer/InnerInstanceEventListener.java | 15 +---- .../consumer/InnerNoticeEventListener.java | 58 +++++++++++++++++- .../consumer/InnerTaskEventListener.java | 59 ++++++++++++++++--- 7 files changed, 209 insertions(+), 37 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java index 23a92d09d..b0bcfaa81 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java @@ -4,22 +4,59 @@ import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import org.springframework.core.Ordered; /** - * TODO + * 消息事件对应mq消息,按照ordered由小到大顺序执行 * * @author wangli * @since 2024/5/27 16:25 */ public interface MessageNotificationListener extends Ordered { + /** + * 站内信推送 + * + * @param messagePushDTO + */ void pushNotice(MessagePushDTO messagePushDTO); + /** + * 待办推送 + * + * @param messagePushDTO + */ void pushPending(MessagePushDTO messagePushDTO); + /** + * 完成待办 + * + * @param messagePushDTO + */ void completePending(MessagePushDTO messagePushDTO); + /** + * 审批失败,恢复待办 + * + * @param messagePushDTO + */ void rollbackPending(MessagePushDTO messagePushDTO); + /** + * 抄送流程 + * + * @param messagePushDTO + */ void carbonCopy(MessagePushDTO messagePushDTO); + /** + * 完成抄送 + * + * @param messagePushDTO + */ void carbonCopyComplete(MessagePushDTO messagePushDTO); + + /** + * 短信推送 + * + * @param messagePushDTO + */ + void pushSms(MessagePushDTO messagePushDTO); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java index f3d956326..9e7e00dc8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java @@ -1,12 +1,35 @@ package cn.axzo.workflow.starter.listener; +import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import org.springframework.core.Ordered; /** - * TODO - * * @author wangli * @since 2024/5/27 16:21 */ public interface ProcessTaskListener extends Ordered { + + /** + * 用户任务已指派审核人 + */ + void onAssigned(ProcessTaskDTO taskDTO); + + /** + * 用户任务已创建,未指派审核人 + */ + void onCreated(ProcessTaskDTO taskDTO); + + /** + * 用户任务已通过 + *

+ * 仅审核通过一个用户任务时触发, 如果任务是驳回了, 则直接走实例撤回事件 + */ + void onCompleted(ProcessTaskDTO taskDTO); + + /** + * 用户任务已删除 + *

+ * 删除不代表驳回或拒绝,因为通过也会走该事件 + */ + void onDeleted(ProcessTaskDTO taskDTO); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java new file mode 100644 index 000000000..37ca7510b --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -0,0 +1,33 @@ +package cn.axzo.workflow.starter.mq.broadcast.consumer; + +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class AbstractWorkflowListener implements WorkflowListener { + + @Autowired + private ObjectProvider> instanceListenersProvider; + + @Autowired + private ListenerExecutor listenerExecutor; + + + protected List getCustomListeners() { + List list = instanceListenersProvider.getIfAvailable(); + if (list == null) { + list = new ArrayList(); + } + return list.stream().sorted(Comparator.comparingInt(Ordered::getOrder)).collect(Collectors.toList()); + } + + protected ListenerExecutor getListenerExecutor() { + return listenerExecutor; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 7973fd8e7..62a539ca4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -5,13 +5,10 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import cn.axzo.workflow.starter.listener.ProcessActivityListener; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -23,7 +20,7 @@ import java.util.function.Consumer; * @since 2024/5/21 15:51 */ @Component -public class InnerActivityEventListener implements WorkflowListener { +public class InnerActivityEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( ProcessActivityEventEnum.PROCESS_ACTIVITY_START.getEventCode(), @@ -32,15 +29,9 @@ public class InnerActivityEventListener implements WorkflowListener { ProcessActivityEventEnum.PROCESS_ACTIVITY_END.getEventCode() ); - @Autowired - private ObjectProvider> activityListenersProvider; - - @Autowired - private ListenerExecutor listenerExecutor; - @Override public void handEvent(Event event, EventConsumer.Context context) { - List activityListeners = activityListenersProvider.getIfAvailable(); + List activityListeners = getCustomListeners(); if (!CollectionUtils.isEmpty(activityListeners)) { ProcessActivityDTO activityDTO = JSON.parseObject(event.getData().toString(), ProcessActivityDTO.class); ProcessActivityEventEnum type = activityDTO.getType(); @@ -62,7 +53,7 @@ public class InnerActivityEventListener implements WorkflowListener { default: log.warn("unknown process activity event type: {}", type); } - listenerExecutor.execute(consumer, activityDTO); + getListenerExecutor().execute(consumer, activityDTO); } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index 8cfd748eb..8150efead 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -5,13 +5,10 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import cn.axzo.workflow.starter.listener.ProcessInstanceListener; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -30,7 +27,7 @@ import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INS * @since 2024/5/21 15:51 */ @Component -public class InnerInstanceEventListener implements WorkflowListener { +public class InnerInstanceEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( PROCESS_INSTANCE_CREATED.getEventCode(), @@ -41,15 +38,9 @@ public class InnerInstanceEventListener implements WorkflowListener { PROCESS_INSTANCE_COMPLETED.getEventCode() ); - @Autowired - private ObjectProvider> activityListenersProvider; - - @Autowired - private ListenerExecutor listenerExecutor; - @Override public void handEvent(Event event, EventConsumer.Context context) { - List instanceListeners = activityListenersProvider.getIfAvailable(); + List instanceListeners = getCustomListeners(); if (!CollectionUtils.isEmpty(instanceListeners)) { ProcessInstanceDTO instanceDTO = JSON.parseObject(event.getData().toString(), ProcessInstanceDTO.class); ProcessInstanceEventEnum type = instanceDTO.getType(); @@ -77,7 +68,7 @@ public class InnerInstanceEventListener implements WorkflowListener { default: log.warn("unknown process activity event type: {}", type); } - listenerExecutor.execute(consumer, instanceDTO); + getListenerExecutor().execute(consumer, instanceDTO); } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java index 76233d96a..634a81777 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java @@ -1,22 +1,26 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import cn.axzo.workflow.starter.listener.MessageNotificationListener; +import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.List; +import java.util.function.Consumer; /** - * TODO - * * @author wangli * @since 2024/5/21 15:53 */ -public class InnerNoticeEventListener { +@Component +public class InnerNoticeEventListener extends AbstractWorkflowListener { private final static Logger log = LoggerFactory.getLogger(InnerNoticeEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( ProcessMessagePushEventEnum.PROCESS_PUSH_NOTICE.getEventCode(), @@ -28,6 +32,49 @@ public class InnerNoticeEventListener { ProcessMessagePushEventEnum.PROCESS_PUSH_SMS.getEventCode() ); + @Override + public void handEvent(Event event, EventConsumer.Context context) { + List instanceListeners = getCustomListeners(); + if (!CollectionUtils.isEmpty(instanceListeners)) { + MessagePushDTO instanceDTO = JSON.parseObject(event.getData().toString(), MessagePushDTO.class); + ProcessMessagePushEventEnum type = instanceDTO.getType(); + for (MessageNotificationListener noticeListener : instanceListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_PUSH_NOTICE: + consumer = noticeListener::pushNotice; + break; + case PROCESS_PUSH_PENDING: + consumer = noticeListener::pushPending; + break; + case PROCESS_PUSH_PENDING_COMPLETE: + consumer = noticeListener::completePending; + break; + case PROCESS_PUSH_PENDING_ROLLBACK: + consumer = noticeListener::rollbackPending; + break; + case PROCESS_CARBON_COPY: + consumer = noticeListener::carbonCopy; + break; + case PROCESS_CARBON_COPY_COMPLETE: + consumer = noticeListener::carbonCopyComplete; + break; + case PROCESS_PUSH_SMS: + consumer = noticeListener::pushSms; + break; + default: + log.warn("unknown message event type: {}", type); + } + getListenerExecutor().execute(consumer, instanceDTO); + } + } + } + + @Override + public boolean support(Event event) { + return event != null && SUPPORTED_EVENT_CODES.contains(event.getEventCode()); + } + public static void main(String[] args) { MessageNotificationListener listener = new MessageNotificationListener() { @Override @@ -64,6 +111,11 @@ public class InnerNoticeEventListener { } + @Override + public void pushSms(MessagePushDTO messagePushDTO) { + + } + public int hashCode() { return super.hashCode(); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index c9d7aa6de..7b8d37665 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -1,25 +1,70 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; +import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; +import cn.axzo.workflow.starter.listener.ProcessTaskListener; +import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.List; +import java.util.function.Consumer; + +import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED; +import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_COMPLETED; +import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_CREATED; +import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_DELETED; /** - * TODO - * * @author wangli * @since 2024/5/21 15:51 */ -public class InnerTaskEventListener { +@Component +public class InnerTaskEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerTaskEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( - ProcessTaskEventEnum.PROCESS_TASK_CREATED.getEventCode(), - ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED.getEventCode(), - ProcessTaskEventEnum.PROCESS_TASK_COMPLETED.getEventCode(), - ProcessTaskEventEnum.PROCESS_TASK_DELETED.getEventCode() + PROCESS_TASK_CREATED.getEventCode(), + PROCESS_TASK_ASSIGNED.getEventCode(), + PROCESS_TASK_COMPLETED.getEventCode(), + PROCESS_TASK_DELETED.getEventCode() ); + + @Override + public void handEvent(Event event, EventConsumer.Context context) { + List taskListeners = getCustomListeners(); + if (!CollectionUtils.isEmpty(taskListeners)) { + ProcessTaskDTO taskDTO = JSON.parseObject(event.getData().toString(), ProcessTaskDTO.class); + ProcessTaskEventEnum type = taskDTO.getType(); + for (ProcessTaskListener taskListener : taskListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_TASK_CREATED: + consumer = taskListener::onCreated; + break; + case PROCESS_TASK_COMPLETED: + consumer = taskListener::onCompleted; + break; + case PROCESS_TASK_ASSIGNED: + consumer = taskListener::onAssigned; + break; + case PROCESS_TASK_DELETED: + consumer = taskListener::onDeleted; + break; + default: + log.warn("unknown task event type: {}", type); + } + getListenerExecutor().execute(consumer, taskDTO); + } + } + } + + @Override + public boolean support(Event event) { + return event != null && SUPPORTED_EVENT_CODES.contains(event.getEventCode()); + } } From db30025235dacec9008bacaed706c751cd7991dd Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 31 May 2024 17:18:11 +0800 Subject: [PATCH 045/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=B8=80=E4=BA=9B=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=AE=8C=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 39 +++++++------------ .../WorkflowEngineStarterProperties.java | 3 +- .../WorkflowEngineBroadcastEventListener.java | 5 ++- .../mq/execute/ListenerExecutorImpl.java | 18 +++++++-- ...rkflowEngineStarterRetryEventListener.java | 2 +- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 9a1ce11da..7c0b1f5b7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,10 +1,9 @@ package cn.axzo.workflow.starter; -import cn.axzo.framework.domain.ServiceException; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import cn.axzo.workflow.starter.mq.execute.ListenerExecutorImpl; -import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; import cn.axzo.workflow.starter.mq.execute.interceptor.FailBackInterceptor; @@ -39,40 +38,28 @@ public class WorkflowEngineStarterAutoConfiguration { @Bean public ListenerExecutor initListenerExecutor(WorkflowEngineStarterProperties starterProperties, List additionalInterceptors) { - FailHandleTypeEnum failHandleType = starterProperties.getFailHandleType(); List interceptors = new ArrayList<>(); interceptors.add(new LogInterceptor()); - interceptors.add(getFailInterceptor(starterProperties, failHandleType)); + interceptors.add(getFailInterceptor(starterProperties)); // if (!CollectionUtils.isEmpty(additionalInterceptors)) { // additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); // } interceptors.add(new ExecutorInvoker()); - return new ListenerExecutorImpl(initInterceptorChain(interceptors)); + return new ListenerExecutorImpl(interceptors); } - private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties, - FailHandleTypeEnum failHandleType) { - if (failHandleType != null) { - switch (failHandleType) { - case FAIL_BACK: - return new FailBackInterceptor(); - case FAIL_FAST: - return new FailFastInterceptor(); - case FAIL_OVER: - return new FailOverInterceptor(starterProperties.getNumOfRetries(), starterProperties.getWaitTimeInMs(), starterProperties.getWaitIncreaseFactor()); - } + private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { + FailHandleTypeEnum failHandleType = starterProperties.getFailHandleType(); + switch (failHandleType) { + case FAIL_BACK: + return new FailBackInterceptor(); + case FAIL_FAST: + return new FailFastInterceptor(); + case FAIL_OVER: + default: + return new FailOverInterceptor(starterProperties.getNumOfRetries(), starterProperties.getWaitTimeInMs(), starterProperties.getWaitIncreaseFactor()); } - return new FailOverInterceptor(starterProperties.getNumOfRetries(), starterProperties.getWaitTimeInMs(), starterProperties.getWaitIncreaseFactor()); } - public ExecuteInterceptor initInterceptorChain(List chain) { - if (chain == null || chain.isEmpty()) { - throw new ServiceException("invalid command interceptor chain configuration: " + chain); - } - for (int i = 0; i < chain.size() - 1; i++) { - chain.get(i).setNext(chain.get(i + 1)); - } - return chain.get(0); - } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 7c58c2228..bce4016b5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; +import static cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum.FAIL_OVER; import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; /** @@ -41,7 +42,7 @@ public class WorkflowEngineStarterProperties { * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行 * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 */ - private FailHandleTypeEnum failHandleType = FailHandleTypeEnum.FAIL_OVER; + private FailHandleTypeEnum failHandleType = FAIL_OVER; /** * 自动重试次数 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 59fa2012d..3ecfdf008 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -14,6 +14,8 @@ import java.util.List; import java.util.Objects; /** + * 流程引擎服务广播的事件监听器 + * * @author wangli * @since 2024/5/21 15:50 */ @@ -29,6 +31,7 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi @Override public void onEvent(Event event, EventConsumer.Context context) { + // TODO 针对事件,区别不同的模型对象处理 MessagePushDTO messagePushDTO = JSON.parseObject(event.getData().toString(), MessagePushDTO.class); if (Objects.isNull(messagePushDTO)) { log.warn("AllMessagePushEventHandler MessagePushDTO is null"); @@ -46,7 +49,7 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi } @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() { eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java index ef39ac4eb..ec177f726 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java @@ -1,19 +1,31 @@ package cn.axzo.workflow.starter.mq.execute; +import cn.axzo.framework.domain.ServiceException; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; +import java.util.List; import java.util.function.Consumer; -public class ListenerExecutorImpl implements ListenerExecutor { +public final class ListenerExecutorImpl implements ListenerExecutor { private final ExecuteInterceptor firstExecuteInterceptor; - public ListenerExecutorImpl(ExecuteInterceptor firstExecuteInterceptor) { - this.firstExecuteInterceptor = firstExecuteInterceptor; + public ListenerExecutorImpl(List chain) { + this.firstExecuteInterceptor = initInterceptorChain(chain); } @Override public void execute(Consumer command, T t) { firstExecuteInterceptor.execute(this, command, t); } + + private ExecuteInterceptor initInterceptorChain(List chain) { + if (chain == null || chain.isEmpty()) { + throw new ServiceException("invalid command interceptor chain configuration: " + chain); + } + for (int i = 0; i < chain.size() - 1; i++) { + chain.get(i).setNext(chain.get(i + 1)); + } + return chain.get(0); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index a3643747d..1160006c4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -22,7 +22,7 @@ import java.util.Map; import java.util.Objects; /** - * RPC 动作事件的 MQ 消费者 + * RPC 动作事件的 MQ 消费者(集成业务系统中的自产自销) * * @author wangli * @since 2024/5/21 16:28 From 45094aef326e11b4f334ea2e874e2ebd36ad29ea Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 31 May 2024 17:19:25 +0800 Subject: [PATCH 046/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=20Decoder?= =?UTF-8?q?=EF=BC=8C=20=E7=94=A8=E6=9D=A5=E5=A4=84=E7=90=86=E6=89=80?= =?UTF-8?q?=E6=9C=89=20API=20=E5=86=85=E9=83=A8=E6=8A=9B=E5=87=BA=E7=9A=84?= =?UTF-8?q?=E5=90=84=E7=B1=BB=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 9 ++- .../starter/api/WorkflowCoreService.java | 3 +- .../ext/WorkflowEngineStarterDecoder.java | 63 +++++++++++++++++++ ...rkflowEngineStarterFeignConfiguration.java | 10 +++ 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 96dc07b76..82e0d6a7b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -144,7 +144,12 @@ public class TestController { workflowCoreService.async(); } } - CommonResponse processInstance = workflowCoreService.createProcessInstance(dto); - return processInstance; + String processInstance = workflowCoreService.createProcessInstance(dto); + return CommonResponse.success(processInstance); + } + + @GetMapping("/test6") + public CommonResponse test6() { + return CommonResponse.success("1"); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index d3a2420b4..626aa989b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -3,7 +3,6 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -24,7 +23,7 @@ import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; public interface WorkflowCoreService { @PostMapping("/api/process/instance/create") - CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); default WorkflowCoreService sync() { ThreadUtil.set(SYNC); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java new file mode 100644 index 000000000..9ba061501 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -0,0 +1,63 @@ +package cn.axzo.workflow.starter.feign.ext; + +import cn.azxo.framework.common.model.CommonResponse; +import feign.Response; +import feign.Util; +import feign.codec.Decoder; + +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Objects; +import java.util.Optional; + +/** + * Workflow Engine Starter Complex Invoke Client Decoder + * + * @author wangli + * @since 2024/5/31 14:55 + */ +public final class WorkflowEngineStarterDecoder implements Decoder { + final Decoder delegate; + + public WorkflowEngineStarterDecoder(Decoder delegate) { + Objects.requireNonNull(delegate, "Decoder must not be null. "); + this.delegate = delegate; + } + + @Override + public Object decode(Response response, Type type) throws IOException { + if (!isOptional(type)) { + return convert(response, type); + } + if (response.status() == 404 || response.status() == 204) { + return Optional.empty(); + } + Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class); + return Optional.ofNullable(convert(response, enclosedType)); + } + + static boolean isOptional(Type type) { + if (!(type instanceof ParameterizedType)) { + return false; + } + ParameterizedType parameterizedType = (ParameterizedType) type; + return parameterizedType.getRawType().equals(Optional.class); + } + + /** + * 这里做返回数据的解析,并处理引擎返回的一些正常的业务异常 + * + * @param response + * @param type + * @param + * @return + */ + T convert(Response response, Type type) throws IOException { + Object decode = delegate.decode(response, type); + if (decode instanceof CommonResponse) { + + } + return null; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 2935f4e34..63792779b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -5,7 +5,12 @@ import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.RequestInterceptor; import feign.Target; +import feign.codec.Decoder; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; +import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; +import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; @@ -30,6 +35,11 @@ public class WorkflowEngineStarterFeignConfiguration { return new ComplexInvokeClient(starterProperties, rpcInvokeEventProducer, feignClient); } + @Bean + public Decoder workflowEngineStarterDecoder(ObjectFactory messageConverters) { + return new WorkflowEngineStarterDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters))); + } + @Bean public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment, From 15656554c26019034b60bf34aea478eec1925237 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 31 May 2024 18:27:15 +0800 Subject: [PATCH 047/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=A4=9A=E4=B8=AA=E6=8E=A5=E5=8F=A3=EF=BC=8C=E7=94=A8?= =?UTF-8?q?=E6=9D=A5=E6=B5=8B=E8=AF=95=E8=BF=94=E5=9B=9E=E5=80=BC=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 40 ++++++++++++++++--- .../starter/api/WorkflowCoreService.java | 14 +++++++ .../ext/WorkflowEngineStarterDecoder.java | 4 +- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 82e0d6a7b..181612720 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; @@ -39,6 +40,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCES /** * 测试接口 + * * @author wangli * @since 2023/10/10 13:59 */ @@ -130,7 +132,7 @@ public class TestController { return CommonResponse.success(true); } - @GetMapping("/test5") + @GetMapping("/create") public CommonResponse test5(@RequestParam(required = false) Boolean sync) { BpmnProcessInstanceCreateDTO dto = new BpmnProcessInstanceCreateDTO(); dto.setProcessDefinitionKey("1"); @@ -144,12 +146,38 @@ public class TestController { workflowCoreService.async(); } } - String processInstance = workflowCoreService.createProcessInstance(dto); - return CommonResponse.success(processInstance); + return CommonResponse.success(workflowCoreService.createProcessInstance(dto)); } - @GetMapping("/test6") - public CommonResponse test6() { - return CommonResponse.success("1"); + @GetMapping("/approve") + public CommonResponse test6(@RequestParam(required = false) Boolean sync, @RequestParam String taskId) { + if (Objects.nonNull(sync)) { + if (sync) { + workflowCoreService.sync(); + } else { + workflowCoreService.async(); + } + } + BpmnTaskAuditDTO dto = new BpmnTaskAuditDTO(); + dto.setTaskId(taskId); + BpmnTaskDelegateAssigner approver = new BpmnTaskDelegateAssigner("2002456", "3", "彭建伦", "9000586", "374", "6064", "https://axzo-app.oss-cn-chengdu.aliyuncs.com/face/face_dev/f5f5634ff6e84bfd9291b8e1a8ad215d.jpg"); + dto.setApprover(approver); + return CommonResponse.success(workflowCoreService.approveTask(dto)); + } + + @GetMapping("/get") + public CommonResponse test7(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) { + if (Objects.nonNull(sync)) { + if (sync) { + workflowCoreService.sync(); + } else { + workflowCoreService.async(); + } + } + BpmnProcessInstanceQueryDTO dto = new BpmnProcessInstanceQueryDTO(); + dto.setProcessInstanceId(processInstanceId); + dto.setHasVariable(true); +// return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto)); + return workflowCoreService.getProcessInstanceVO(dto); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 626aa989b..e552c953d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,10 +1,16 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.azxo.framework.common.model.CommonResponse; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -25,6 +31,14 @@ public interface WorkflowCoreService { @PostMapping("/api/process/instance/create") String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") + @PostMapping("/api/process/task/approve") + Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + @Operation(summary = "获得流程实例") + @GetMapping("/api/process/instance/get") + CommonResponse getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + default WorkflowCoreService sync() { ThreadUtil.set(SYNC); return this; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 9ba061501..4510d08cd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -53,11 +53,11 @@ public final class WorkflowEngineStarterDecoder implements Decoder { * @param * @return */ - T convert(Response response, Type type) throws IOException { + Object convert(Response response, Type type) throws IOException { Object decode = delegate.decode(response, type); if (decode instanceof CommonResponse) { } - return null; + return decode; } } From fc05f5ff63723726ae79d765c4d24e2c52c47af7 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 31 May 2024 18:28:38 +0800 Subject: [PATCH 048/210] =?UTF-8?q?update=20-=20REQ-2516-=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E5=A4=9A=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineBroadcastEventListener.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 3ecfdf008..33a612fe8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -3,15 +3,12 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; -import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.CollectionUtils; import java.util.List; -import java.util.Objects; /** * 流程引擎服务广播的事件监听器 @@ -31,14 +28,8 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi @Override public void onEvent(Event event, EventConsumer.Context context) { - // TODO 针对事件,区别不同的模型对象处理 - MessagePushDTO messagePushDTO = JSON.parseObject(event.getData().toString(), MessagePushDTO.class); - if (Objects.isNull(messagePushDTO)) { - log.warn("AllMessagePushEventHandler MessagePushDTO is null"); - return; - } if (CollectionUtils.isEmpty(workflowListeners)) { - log.warn("AllWorkflowListener is null,msg:{}", JSON.toJSONString(event)); + log.warn("no workflow listener to handle event: {}", event); return; } for (WorkflowListener workflowListener : workflowListeners) { From 95bee3c5862b2386e812a932dde6620ceb1fa014 Mon Sep 17 00:00:00 2001 From: wangli Date: Sat, 1 Jun 2024 18:52:36 +0800 Subject: [PATCH 049/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20RPC=20=E5=8A=A8=E4=BD=9C=E5=BC=82=E6=AD=A5=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E8=A1=8C=E4=B8=BA,=20=E7=A1=AE=E4=BF=9D=E5=8F=AA?= =?UTF-8?q?=E6=9C=89=E5=9C=A8=E7=BD=91=E7=BB=9C=E8=BF=9E=E6=8E=A5=E5=BC=82?= =?UTF-8?q?=E5=B8=B8,=E6=89=8D=E8=BF=9B=E8=A1=8C=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/WorkflowRequestInterceptor.java | 6 ++--- .../server/controller/web/TestController.java | 5 +++- .../WorkflowEngineStarterProperties.java | 8 ++++-- ...lowEngineStarterRocketMQConfiguration.java | 1 + .../starter/api/WorkflowCoreService.java | 3 +-- .../common/constant/StarterConstants.java | 2 +- .../feign/ext/ComplexInvokeClient.java | 21 ++++++---------- .../ext/WorkflowEngineStarterDecoder.java | 19 +++++++++++--- ...rkflowEngineStarterFeignConfiguration.java | 14 ++++++++++- ...rkflowEngineStarterRetryEventListener.java | 25 ++++++++++++++++--- 10 files changed, 72 insertions(+), 32 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java index ea35fc79f..bd7533f16 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java @@ -17,9 +17,9 @@ public class WorkflowRequestInterceptor implements RequestInterceptor { this.serviceVersion = serviceVersion; } - public static final String HEADER_HTTP_CLIENT = "http-client"; - public static final String HEADER_HTTP_CLIENT_VALUE = "workflowEngine-feign"; - public static final String HEADER_API_VERSION = "service-version"; + public static final String HEADER_HTTP_CLIENT = "Http-Client"; + public static final String HEADER_HTTP_CLIENT_VALUE = "WorkflowEngine-Feign"; + public static final String HEADER_API_VERSION = "Service-Version"; public static final String HEADER_SERVER_NAME = "X-SERVER-NAME"; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 181612720..9b876aae5 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -167,6 +167,9 @@ public class TestController { @GetMapping("/get") public CommonResponse test7(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) { + if (Objects.isNull(sync)) { + throw new RuntimeException("sync 参数不能为空"); + } if (Objects.nonNull(sync)) { if (sync) { workflowCoreService.sync(); @@ -178,6 +181,6 @@ public class TestController { dto.setProcessInstanceId(processInstanceId); dto.setHasVariable(true); // return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto)); - return workflowCoreService.getProcessInstanceVO(dto); + return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto)); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index bce4016b5..448df3bb7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -22,25 +22,29 @@ public class WorkflowEngineStarterProperties { /** * 本地启动是否消费容器的广播事件 - *

+ *

      * 默认 false, 本地启动应用时, 将创建消息组名称中含有"debugging"的消费组.
      * 否则, 本地启动应用时, 将与容器环境中所有实例共同消费广播事件.
+     * 
*/ private Boolean localConsumer = false; /** * WorkflowCoreService 类中所有方法调用时默认采用的模式 - *

+ *

      * 如果是同步调用,则直接通过普通 FeignClient 进行调用,
      * 否则将通过 MQ 将 RPC 调用进行解耦
+     * 
*/ private RpcInvokeModeEnum invokeMode = ASYNC; /** * 失败处理策略: + *
      * 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略)
      * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行
      * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持
+     * 
*/ private FailHandleTypeEnum failHandleType = FAIL_OVER; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index 949794a62..2e7f71a54 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -170,6 +170,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, + maxReconsumeTimes = 3, // TODO 发布时需调整为 7, 总共耗时在 15min 内 replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index e552c953d..025c72181 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -6,7 +6,6 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; @@ -37,7 +36,7 @@ public interface WorkflowCoreService { @Operation(summary = "获得流程实例") @GetMapping("/api/process/instance/get") - CommonResponse getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); default WorkflowCoreService sync() { ThreadUtil.set(SYNC); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java index d186f8765..25e16379a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java @@ -7,5 +7,5 @@ package cn.axzo.workflow.starter.common.constant; * @since 2024/5/29 11:13 */ public interface StarterConstants { - String STARTER_INVOKE_MODE = "Workflow-Engine-Starter-Invoke-Mode"; + String STARTER_INVOKE_MODE = "WORKFLOW-ENGINE-STARTER-INVOKE-MODE"; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index d5b72a718..ac5bef54f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -14,6 +14,7 @@ import feign.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; +import org.springframework.util.CollectionUtils; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -60,26 +61,18 @@ public class ComplexInvokeClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { log.info("ComplexInvokeClient execute..."); - RpcInvokeModeEnum currentInvokeModeEnum = ThreadUtil.get(); + RpcInvokeModeEnum currentInvokeModeEnum = getInvokeMode(request); - if (Objects.isNull(currentInvokeModeEnum)) { - log.info("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in StarterProperties will be loaded."); - currentInvokeModeEnum = getDefaultInvokeMode(request); - } + Map> headers = request.headers(); + headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); - log.info("final InvokeMode : {}", currentInvokeModeEnum); if (Objects.equals(SYNC, currentInvokeModeEnum)) { log.info("[sync] invoke..."); ThreadUtil.clear(); return feignClient.execute(request, options); } - - Map> headers = request.headers(); - headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); - asyncInvoke(request); - return Response.builder() .status(HttpStatus.OK.value()) .reason(HttpStatus.OK.getReasonPhrase()) @@ -109,10 +102,10 @@ public class ComplexInvokeClient implements Client { rpcInvokeEventProducer.send(WORKFLOW_ENGINE_STARTER, event); } - private RpcInvokeModeEnum getDefaultInvokeMode(Request request) { + private RpcInvokeModeEnum getInvokeMode(Request request) { Collection invokeModel = request.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.singletonList(starterProperties.getInvokeMode().name())); - if (invokeModel == null || invokeModel.isEmpty()) { + if (CollectionUtils.isEmpty(invokeModel)) { return starterProperties.getInvokeMode(); } else if (invokeModel.size() > 1) { throw new WorkflowEngineStarterException("Multiple invoke mode is not supported"); @@ -121,7 +114,7 @@ public class ComplexInvokeClient implements Client { } static Response.Body body = new Response.Body() { - final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success("Send MQ Success")) + final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success(HttpStatus.OK.value(), "Send MQ Success", null)) .getBytes(StandardCharsets.UTF_8)); @Override diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 4510d08cd..373611466 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -4,6 +4,9 @@ import cn.azxo.framework.common.model.CommonResponse; import feign.Response; import feign.Util; import feign.codec.Decoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.io.IOException; import java.lang.reflect.ParameterizedType; @@ -17,7 +20,8 @@ import java.util.Optional; * @author wangli * @since 2024/5/31 14:55 */ -public final class WorkflowEngineStarterDecoder implements Decoder { +final class WorkflowEngineStarterDecoder implements Decoder { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterDecoder.class); final Decoder delegate; public WorkflowEngineStarterDecoder(Decoder delegate) { @@ -50,13 +54,20 @@ public final class WorkflowEngineStarterDecoder implements Decoder { * * @param response * @param type - * @param * @return */ Object convert(Response response, Type type) throws IOException { - Object decode = delegate.decode(response, type); + if (type instanceof ParameterizedType) { + return delegate.decode(response, type); + } + ParameterizedTypeImpl wrappedType = ParameterizedTypeImpl.make(CommonResponse.class, new Type[]{type}, null); + Object decode = delegate.decode(response, wrappedType); if (decode instanceof CommonResponse) { - + CommonResponse commonResponse = (CommonResponse) decode; + if (response.status() == 202) { + log.warn("workflow engine starter rpc async invoke return msg: {}", commonResponse.getMsg()); + } + return commonResponse.getData(); } return decode; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 63792779b..e6dce0759 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -1,11 +1,15 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; +import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.RequestInterceptor; import feign.Target; import feign.codec.Decoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; @@ -14,6 +18,8 @@ import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; +import java.util.Objects; + import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; @@ -27,6 +33,7 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_ * @since 2024/5/28 23:17 */ public class WorkflowEngineStarterFeignConfiguration { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterFeignConfiguration.class); @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, @@ -46,7 +53,12 @@ public class WorkflowEngineStarterFeignConfiguration { String serviceVersion) { return template -> { template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); - template.header(STARTER_INVOKE_MODE, starterProperties.getInvokeMode().name()); + RpcInvokeModeEnum rpcInvokeModeEnum = ThreadUtil.get(); + if (Objects.isNull(rpcInvokeModeEnum)) { + log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); + rpcInvokeModeEnum = starterProperties.getInvokeMode(); + } + template.header(STARTER_INVOKE_MODE, rpcInvokeModeEnum.name()); Target.HardCodedTarget target = (Target.HardCodedTarget) template.feignTarget(); String apiClassPath = target.type().getName(); if (apiClassPath.contains("cn.axzo.workflow.starter.api")) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 1160006c4..cc13a83e3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -4,7 +4,6 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.starter.api.WorkflowCoreService; import com.alibaba.fastjson.JSON; @@ -17,6 +16,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; import java.lang.reflect.Method; +import java.net.ConnectException; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -85,13 +85,30 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In } try { workflowCoreService.sync(); - Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), BpmnProcessInstanceCreateDTO.class)); + // TODO 入参需要根据类型进行转换 + Class parameterType = method.getParameterTypes()[0]; + Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), parameterType)); log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); - } catch (Exception e) { - log.error("Event Invoke Exception: {}", e.getMessage(), e); + } catch (Throwable e) { + // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 + Throwable cause = getRealCause(e); + log.error("Event Invoke Exception: {}", cause.getMessage(), cause); + if (cause instanceof ConnectException) { + // 而只有当网络异常时, 利用 RocketMQ 的重试机制 + throw cause; + } } } + private Throwable getRealCause(Throwable error) { + while (Objects.nonNull(error.getCause())) { + // TODO 如果有必要, 可以在这里对异常进行判断/过滤之类的动作, 目前暂未发现需要处理的场景, + // 后续如果发现, 则需要在此处进行扩展, 注意不是 HardCode, 而是用接口扩展 + error = error.getCause(); + } + return error; + } + @Override public void afterPropertiesSet() { workflowEngineStarterEventConsumer.registerHandler(WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER.getEventCode(currentApplicationName), this); From c471d787f6ebbfcbcaaf45467ef8afc3e3e4e8e5 Mon Sep 17 00:00:00 2001 From: wangli Date: Sat, 1 Jun 2024 22:56:44 +0800 Subject: [PATCH 050/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E6=9C=AC=E5=9C=B0=E5=90=AF=E7=94=A8=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E6=97=B6=20MQ=20=E5=8A=A0=E5=85=A5=E5=AE=B9=E5=99=A8=E9=9B=86?= =?UTF-8?q?=E7=BE=A4=E6=B6=88=E8=B4=B9=E7=9A=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...lowEngineStarterRocketMQConfiguration.java | 4 +- .../NonContainerEnvironmentCondition.java | 59 +++++++++++++------ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index 2e7f71a54..a5c7f785f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -82,7 +82,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { @Component @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_${MY_POD_NAMESPACE:debugging}_consumer", + consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) @@ -168,7 +168,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { @Component @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${MY_POD_NAMESPACE:debugging}_consumer", + consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, maxReconsumeTimes = 3, // TODO 发布时需调整为 7, 总共耗时在 15min 内 replyTimeout = 10000, diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java index 622fb40ae..15d1cdfcc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java @@ -11,13 +11,16 @@ import org.springframework.util.StringUtils; import java.util.Objects; +import static cn.axzo.workflow.starter.common.constant.StarterConstants.DEBUGGING_MQ_SUFFIX; +import static cn.axzo.workflow.starter.common.constant.StarterConstants.K8S_POD_NAME_SPACE; +import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; + /** * 用于处理 MQ 的消费者, 在本地启动或在容器中启动时, 能自主控制是否并入统一的消费组 *

- * 可查看 {@link WorkflowEngineStarterProperties#localConsumer} 属性, 来了解本来的用途, - * 特别需要注意的是: Starter 是结合 K8S 的 命名空间(namespace) 来处理的. 如果公司在删减/变更 - * 环境后,可能会导致 {@link NonContainerEnvironmentCondition#mappingNamespace(String)} - * 方法异常. + * 可查看 {@link WorkflowEngineStarterProperties#joinContainerGroup} 属性, 来了解本类的用途, + * 特别需要注意的是: Starter 是结合 K8S 的命名空间(namespace) 来处理的. 如果公司在变更环境后, + * 可能会导致 {@link NonContainerEnvironmentCondition#mappingNamespace(String)} 方法异常. * * @author wangli * @since 2024/5/30 22:19 @@ -26,32 +29,49 @@ public class NonContainerEnvironmentCondition implements Condition { private static final Logger log = LoggerFactory.getLogger(NonContainerEnvironmentCondition.class); - private static final String MY_POD_NAMESPACE = "MY_POD_NAMESPACE"; - @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment(); - // 优先外部化配置 - Boolean localCustomer = environment.getProperty("workflow.engine.starter.local-consumer", Boolean.class); - if (Objects.isNull(localCustomer)) { - // 获取默认值 - localCustomer = new WorkflowEngineStarterProperties().getLocalConsumer(); - } - log.info("workflow engine starter local consumer status: {}", localCustomer); + String myPodNamespace = environment.getProperty(K8S_POD_NAME_SPACE); - String myPodNamespace = environment.getProperty(MY_POD_NAMESPACE); - if (localCustomer && !StringUtils.hasText(myPodNamespace)) { - environment.getSystemProperties().put(MY_POD_NAMESPACE, mappingNamespace(environment.getProperty("spring.profiles.active"))); + // 在容器环境时, 强制加入集群消费组 + if (StringUtils.hasText(myPodNamespace)) { + environment.getSystemProperties().put(MQ_GID_NAME_SEGMENT, mappingNamespace(myPodNamespace)); + return true; } + + // 优先外部化配置 + Boolean joinContainerGroup = environment.getProperty("workflow.engine.starter.join-container-group", Boolean.class); + if (Objects.isNull(joinContainerGroup)) { + // 获取默认值 + joinContainerGroup = new WorkflowEngineStarterProperties().getJoinContainerGroup(); + } + log.debug("workflow engine starter join-container-group status: {} ", joinContainerGroup); + + String activeProfile = environment.getProperty("spring.profiles.active", String.class); + environment.getSystemProperties().put(MQ_GID_NAME_SEGMENT, + joinContainerGroup ? mappingNamespace(activeProfile) : activeProfile + DEBUGGING_MQ_SUFFIX); + return true; } + /** + * 将 K8S 集群的 NameSpace 空间名映射为开发常用的 profile 名称 + * + * @param namespace + * @return + */ private String mappingNamespace(String namespace) { + if (!StringUtils.hasText(namespace)) { + throw new IllegalArgumentException("namespace is empty"); + } switch (namespace) { - case "dev": case "local": - return "java-dev"; + return "local"; + case "dev": + case "java-dev": + return "dev"; case "test": return "test"; case "pre": @@ -59,7 +79,8 @@ public class NonContainerEnvironmentCondition implements Condition { case "live": return "live"; case "master": - return "pro"; + case "pro": + return "master"; default: throw new IllegalArgumentException(String.format("namespace %s is not supported", namespace)); } From 30b151ca9aaa2caff54e02b8f6a212f039c5ab14 Mon Sep 17 00:00:00 2001 From: wangli Date: Sat, 1 Jun 2024 22:59:50 +0800 Subject: [PATCH 051/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=92=88?= =?UTF-8?q?=E5=AF=B9=20RPC=20=E8=B0=83=E7=94=A8=E7=9A=84=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=BC=82=E6=AD=A5,=E8=BF=9B=E8=A1=8C=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/annotation/InvokeMode.java | 28 +++++++++++++++++++ .../common/enums/RpcInvokeModeEnum.java | 4 +-- .../workflow}/common/util/ThreadUtil.java | 5 ++-- .../WorkflowEngineStarterProperties.java | 27 +++++++++++------- .../starter/api/WorkflowCoreService.java | 9 ++++-- .../common/constant/StarterConstants.java | 3 ++ .../feign/ext/ComplexInvokeClient.java | 6 ++-- ...rkflowEngineStarterFeignConfiguration.java | 4 +-- ...orkflowEngineStarterInvocationHandler.java | 13 +++++++++ ...rkflowEngineStarterRetryEventListener.java | 6 +++- 10 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/InvokeMode.java rename {workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter => workflow-engine-common/src/main/java/cn/axzo/workflow}/common/enums/RpcInvokeModeEnum.java (63%) rename {workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter => workflow-engine-common/src/main/java/cn/axzo/workflow}/common/util/ThreadUtil.java (80%) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/InvokeMode.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/InvokeMode.java new file mode 100644 index 000000000..26a45dcf6 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/InvokeMode.java @@ -0,0 +1,28 @@ +package cn.axzo.workflow.common.annotation; + +import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; + +/** + * 用于标记接口的方法调用模式 + * + * @author wangli + * @since 2024/6/1 19:01 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface InvokeMode { + + /** + * 调用模式, 默认异步 + */ + RpcInvokeModeEnum value() default ASYNC; +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/RpcInvokeModeEnum.java similarity index 63% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java rename to workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/RpcInvokeModeEnum.java index 1e6c0e778..4a8f4c439 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/enums/RpcInvokeModeEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/RpcInvokeModeEnum.java @@ -1,7 +1,7 @@ -package cn.axzo.workflow.starter.common.enums; +package cn.axzo.workflow.common.enums; /** - * TODO + * PRC 调用模式枚举 * * @author wangli * @since 2024/5/29 10:27 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/util/ThreadUtil.java similarity index 80% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java rename to workflow-engine-common/src/main/java/cn/axzo/workflow/common/util/ThreadUtil.java index 59acedc08..6a4f1458c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/util/ThreadUtil.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/util/ThreadUtil.java @@ -1,6 +1,7 @@ -package cn.axzo.workflow.starter.common.util; +package cn.axzo.workflow.common.util; -import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; + +import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; /** * TODO diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 448df3bb7..5ed2be18b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -1,11 +1,13 @@ package cn.axzo.workflow.starter; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; +import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; -import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum.FAIL_OVER; -import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; /** * Workflow Engine Starter Properties @@ -21,20 +23,25 @@ public class WorkflowEngineStarterProperties { private Boolean manageable = false; /** - * 本地启动是否消费容器的广播事件 + *

该参数只针对容器环境生效

+ * 本地启动时,是否将本地的 MQ 消费者加入集群消费组 *
      * 默认 false, 本地启动应用时, 将创建消息组名称中含有"debugging"的消费组.
-     * 否则, 本地启动应用时, 将与容器环境中所有实例共同消费广播事件.
+     * 否则, 本地启动应用时, 消费者将加入容器环境, 进行集群消费.
      * 
*/ - private Boolean localConsumer = false; + private Boolean joinContainerGroup = false; /** - * WorkflowCoreService 类中所有方法调用时默认采用的模式 + * WorkflowCoreService 类中所有方法未标记{@link InvokeMode}注解的方法调用时, 默认采用的模式 + * *
      * 如果是同步调用,则直接通过普通 FeignClient 进行调用,
      * 否则将通过 MQ 将 RPC 调用进行解耦
      * 
+ *

+ * 如果方法上有{@link InvokeMode}注解, 则以注解上的模式优先, 如果还想覆盖注解中的模式, + * 则可以通过 {@link WorkflowCoreService#sync()}或{@link WorkflowCoreService#async()}方法进行覆盖 */ private RpcInvokeModeEnum invokeMode = ASYNC; @@ -77,12 +84,12 @@ public class WorkflowEngineStarterProperties { this.manageable = manageable; } - public Boolean getLocalConsumer() { - return localConsumer; + public Boolean getJoinContainerGroup() { + return joinContainerGroup; } - public void setLocalConsumer(Boolean localConsumer) { - this.localConsumer = localConsumer; + public void setJoinContainerGroup(Boolean joinContainerGroup) { + this.joinContainerGroup = joinContainerGroup; } public RpcInvokeModeEnum getInvokeMode() { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 025c72181..91ca6014b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,10 +1,11 @@ package cn.axzo.workflow.starter.api; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.starter.common.util.ThreadUtil; +import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; @@ -13,8 +14,9 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * 模拟生成的受限访问的接口定义 @@ -28,6 +30,7 @@ import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; public interface WorkflowCoreService { @PostMapping("/api/process/instance/create") + @InvokeMode(SYNC) String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java index 25e16379a..b74c66ddb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java @@ -8,4 +8,7 @@ package cn.axzo.workflow.starter.common.constant; */ public interface StarterConstants { String STARTER_INVOKE_MODE = "WORKFLOW-ENGINE-STARTER-INVOKE-MODE"; + String DEBUGGING_MQ_SUFFIX = "_debugging"; + String K8S_POD_NAME_SPACE = "MY_POD_NAMESPACE"; + String MQ_GID_NAME_SEGMENT = "GID_SEGMENT"; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index ac5bef54f..ca230592a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,10 +1,10 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; +import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; -import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; @@ -31,9 +31,9 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Stream; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; -import static cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum.SYNC; /** * 适用于 Starter 中复合型的 FeignClient 实现 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index e6dce0759..5b57303bc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -1,8 +1,8 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; +import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.common.enums.RpcInvokeModeEnum; -import cn.axzo.workflow.starter.common.util.ThreadUtil; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.RequestInterceptor; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java index b8bc5a5c5..235ce890a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -1,12 +1,16 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.util.ThreadUtil; import feign.InvocationHandlerFactory; import feign.Target; +import org.springframework.core.annotation.AnnotationUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Map; +import java.util.Objects; /** * Workflow Engine Starter Core Service Invocation Handler @@ -40,9 +44,18 @@ class WorkflowEngineStarterInvocationHandler implements InvocationHandler { return toString(); } + parseInvokeModelAnnotation(method); + return dispatch.get(method).invoke(args); } + private static void parseInvokeModelAnnotation(Method method) { + InvokeMode annotation = AnnotationUtils.getAnnotation(method, InvokeMode.class); + if (Objects.nonNull(annotation)) { + ThreadUtil.set(annotation.value()); + } + } + @Override public boolean equals(Object obj) { if (obj instanceof WorkflowEngineStarterInvocationHandler) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index cc13a83e3..2d65be7a6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -5,6 +5,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; +import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.api.WorkflowCoreService; import com.alibaba.fastjson.JSON; import lombok.SneakyThrows; @@ -21,6 +22,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * RPC 动作事件的 MQ 消费者(集成业务系统中的自产自销) * @@ -84,7 +87,8 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In throw new IllegalStateException("Not found method:" + dto.getMethodName()); } try { - workflowCoreService.sync(); + // 事件处理 RPC 请求, 强制使用同步模式 + ThreadUtil.set(SYNC); // TODO 入参需要根据类型进行转换 Class parameterType = method.getParameterTypes()[0]; Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), parameterType)); From 08a119760980bcf302331451c5732e72ebb3fa7a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 3 Jun 2024 14:57:15 +0800 Subject: [PATCH 052/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=20RPC=20=E5=8A=A8=E4=BD=9C=E4=B8=AD=EF=BC=8C=E5=AF=B9?= =?UTF-8?q?=20Event=20=E5=8F=82=E6=95=B0=E7=9A=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessInstanceApi.java | 1 - .../client/feign/bpmn/ProcessTaskApi.java | 7 +- .../request/bpmn/BpmnProcessVariable.java | 6 +- .../request/bpmn/RestBpmnProcessVariable.java | 2 +- .../mq/WorkflowEngineStarterRpcInvokeDTO.java | 33 +---- .../server/controller/web/TestController.java | 36 +++++ ...orkflowEngineStarterAutoConfiguration.java | 5 +- .../starter/api/WorkflowCoreService.java | 17 +++ .../WorkflowRequestParserException.java | 13 ++ .../feign/ext/ComplexInvokeClient.java | 127 ++++++++++++++++-- ...orkflowEngineStarterInvocationHandler.java | 2 +- ...rkflowEngineStarterRetryEventListener.java | 14 +- 12 files changed, 211 insertions(+), 52 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index 006bd9277..f594c9362 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -19,7 +19,6 @@ import cn.axzo.workflow.generate.annotition.GenService; import cn.azxo.framework.common.model.CommonResponse; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index f34fbb641..a051577f2 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -28,7 +28,7 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.annotation.Nullable; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.NotEmpty; import java.util.List; import java.util.Map; @@ -82,7 +82,8 @@ public interface ProcessTaskApi { */ @Operation(summary = "获取实例正在审核的人列表") @GetMapping("/api/process/task/active/list") - CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @NotBlank(message = "租户不能为空") @RequestParam String tenantId); /** * 同意 @@ -228,6 +229,6 @@ public interface ProcessTaskApi { */ @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/batch/find") - CommonResponse> findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotNull(message = "流程实例 ID列表 不能为空") List processInstanceIds, + CommonResponse> findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnProcessVariable.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnProcessVariable.java index 125df6b66..149602ce8 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnProcessVariable.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnProcessVariable.java @@ -22,9 +22,9 @@ public class BpmnProcessVariable { @NotBlank(message = "流程变量名称不能为空") private String name; - @ApiModelProperty(value = "流程变量类型") - @NotBlank(message = "流程变量类型不能为空") - private String type; +// @ApiModelProperty(value = "流程变量类型") +// @NotBlank(message = "流程变量类型不能为空") +// private String type; @ApiModelProperty(value = "流程变量值") @NotNull(message = "流程变量值不能为空") diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/RestBpmnProcessVariable.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/RestBpmnProcessVariable.java index 1a5a8ae5b..615330700 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/RestBpmnProcessVariable.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/RestBpmnProcessVariable.java @@ -20,7 +20,7 @@ public class RestBpmnProcessVariable extends BpmnProcessVariable { /** * 变量作用域, 目前支持 LOCAL(局部变量) 和 GLOBAL(全局变量) */ - private RestVariableScope scope; + private RestVariableScope scope = RestVariableScope.GLOBAL; public String getVariableScope() { String scope = null; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java index a596cdd51..954e386a1 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java @@ -1,7 +1,7 @@ package cn.axzo.workflow.common.model.response.mq; import java.io.Serializable; -import java.util.List; +import java.util.Map; /** * Starter RPC 调用事件模型 @@ -16,12 +16,7 @@ public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { private String methodName; - private List parameterTypes; - - private String originUrl; - - private Object body; - + private Map, Object> parameters; public String getClassName() { return className; @@ -39,27 +34,11 @@ public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { this.methodName = methodName; } - public List getParameterTypes() { - return parameterTypes; + public Map, Object> getParameters() { + return parameters; } - public void setParameterTypes(List parameterTypes) { - this.parameterTypes = parameterTypes; - } - - public String getOriginUrl() { - return originUrl; - } - - public void setOriginUrl(String originUrl) { - this.originUrl = originUrl; - } - - public Object getBody() { - return body; - } - - public void setBody(Object body) { - this.body = body; + public void setParameters(Map, Object> parameters) { + this.parameters = parameters; } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 9b876aae5..85ff8c8c3 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.server.controller.web; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; @@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController; import java.io.InputStream; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -183,4 +185,38 @@ public class TestController { // return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto)); return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto)); } + + @GetMapping("/get/vars") + public CommonResponse> test8(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) { + if (Objects.isNull(sync)) { + throw new RuntimeException("sync 参数不能为空"); + } + if (Objects.nonNull(sync)) { + if (sync) { + workflowCoreService.sync(); + } else { + workflowCoreService.async(); + } + } + return CommonResponse.success(workflowCoreService.getProcessVariables(processInstanceId, null)); + } + + @GetMapping("/create/var") + public CommonResponse test9(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) { + if (Objects.isNull(sync)) { + throw new RuntimeException("sync 参数不能为 null"); + } + if (Objects.nonNull(sync)) { + if (sync) { + workflowCoreService.sync(); + } else { + workflowCoreService.async(); + } + } + RestBpmnProcessVariable variable = new RestBpmnProcessVariable(); + variable.setName("testVar"); + variable.setValue("testValue"); + workflowCoreService.createVariable(processInstanceId, variable); + return CommonResponse.success(null); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 7c0b1f5b7..2142b3088 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -50,6 +50,7 @@ public class WorkflowEngineStarterAutoConfiguration { private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { FailHandleTypeEnum failHandleType = starterProperties.getFailHandleType(); + log.info("workflow engine starter fail handle type : {}", failHandleType); switch (failHandleType) { case FAIL_BACK: return new FailBackInterceptor(); @@ -57,7 +58,9 @@ public class WorkflowEngineStarterAutoConfiguration { return new FailFastInterceptor(); case FAIL_OVER: default: - return new FailOverInterceptor(starterProperties.getNumOfRetries(), starterProperties.getWaitTimeInMs(), starterProperties.getWaitIncreaseFactor()); + return new FailOverInterceptor(starterProperties.getNumOfRetries(), + starterProperties.getWaitTimeInMs(), + starterProperties.getWaitIncreaseFactor()); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 91ca6014b..f387f5002 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; @@ -11,8 +12,14 @@ import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotBlank; +import java.util.Map; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; @@ -41,6 +48,16 @@ public interface WorkflowCoreService { @GetMapping("/api/process/instance/get") BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + @Operation(summary = "获取指定流程实例的流程变量") + @GetMapping("/api/process/instance/cooperation-org") + Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + @Operation(summary = "为指定流程新增变量") + @PostMapping("/api/process/variable/create/{executionId}") + void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, + @RequestBody @Validated RestBpmnProcessVariable restVariable); + default WorkflowCoreService sync() { ThreadUtil.set(SYNC); return this; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java new file mode 100644 index 000000000..15bb4142c --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * 工作流 RPC 动作异步,解析 feign.Request 中 HTTP 协议的请求参数异常 + * + * @author wangli + * @since 2024/6/3 10:48 + */ +public class WorkflowRequestParserException extends RuntimeException { + public WorkflowRequestParserException(String message) { + super(message); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index ca230592a..aebf1c95b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -9,31 +9,44 @@ import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; import feign.Client; +import feign.MethodMetadata; import feign.Request; import feign.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; +import java.util.HashMap; +import java.util.LinkedList; import java.util.Map; import java.util.Objects; -import java.util.stream.Stream; +import java.util.Queue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; +import static java.nio.charset.StandardCharsets.UTF_8; /** * 适用于 Starter 中复合型的 FeignClient 实现 @@ -90,18 +103,108 @@ public class ComplexInvokeClient implements Client { private void asyncInvoke(Request request) { log.info("[async] invoke..."); WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); - event.setClassName(request.requestTemplate().feignTarget().type().getName()); - event.setMethodName(request.requestTemplate().methodMetadata().method().getName()); + MethodMetadata metadata = request.requestTemplate().methodMetadata(); + event.setClassName(metadata.targetType().getName()); + event.setMethodName(metadata.method().getName()); - List types = new ArrayList<>(); - Stream.of(request.requestTemplate().methodMetadata().method().getParameterTypes()).forEach(p -> types.add(p.getName())); - event.setParameterTypes(types); + Map, Object> args = new HashMap<>(); + event.setParameters(args); + buildArgs(request, metadata, args); - event.setOriginUrl(request.url()); - event.setBody(new String(request.body(), StandardCharsets.UTF_8)); rpcInvokeEventProducer.send(WORKFLOW_ENGINE_STARTER, event); } + private void buildArgs(Request request, MethodMetadata metadata, Map, Object> args) { + Parameter[] parameters = metadata.method().getParameters(); + Class[] parameterTypes = metadata.method().getParameterTypes(); + Annotation[][] parameterAnnotations = metadata.method().getParameterAnnotations(); + Map> queries = request.requestTemplate().queries(); + byte[] body = request.requestTemplate().body(); + + // 提前解析出 PathVariable 变量,避免后续循环时再解析 + Map pathVariableMap = parsePathVariables(getRequestMappingsValue(metadata.method()), getUrlRemoveDomain(request)); + Queue pathVariableQueue = convertMapValueToQueue(pathVariableMap); + for (int i = 0; i < parameters.length; i++) { + // 目前工作流的所有 API,只用了 RequestParam / RequestBody / PathVariable 三个注解,所以这里只处理这三种 + Parameter parameter = parameters[i]; + Class parameterType = parameterTypes[i]; + Annotation[] annotations = parameterAnnotations[i]; + for (Annotation annotation : annotations) { + if (annotation instanceof RequestParam) { + args.put(parameterType, parameterType.cast(queries.getOrDefault(parameter.getName(), Collections.emptyList()))); + } else if (annotation instanceof PathVariable) { + args.put(parameterType, parameterType.cast(pathVariableQueue.poll())); + } else if (annotation instanceof RequestBody) { + args.put(parameterType, new String(body, UTF_8)); + } else { + log.warn("annotation is not supported: {}", annotation); + } + } + } + } + + private String getRequestMappingsValue(Method method) { + Annotation[] annotations = method.getAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof GetMapping) { + GetMapping getMapping = (GetMapping) annotation; + return getMapping.value()[0]; + } else if (annotation instanceof PostMapping) { + PostMapping postMapping = (PostMapping) annotation; + return postMapping.value()[0]; + } else if (annotation instanceof PutMapping) { + PutMapping putMapping = (PutMapping) annotation; + return putMapping.value()[0]; + } else if (annotation instanceof DeleteMapping) { + DeleteMapping deleteMapping = (DeleteMapping) annotation; + return deleteMapping.value()[0]; + } + } + if (log.isDebugEnabled()) { + log.debug("{} not found request mappings", method.getName()); + } + return ""; + } + + private String getUrlRemoveDomain(Request request) { + return request.url().replace(request.requestTemplate().feignTarget().url(), ""); + } + + private Queue convertMapValueToQueue(Map map) { + Queue queue = new LinkedList<>(); + if (CollectionUtils.isEmpty(map)) { + return queue; + } + map.forEach((k, v) -> queue.add(v)); + return queue; + } + + private Map parsePathVariables(String template, String actualPath) { + Map variables = new HashMap<>(); + + // 创建一个正则表达式,用于匹配模板中的占位符 + String regex = template.replaceAll("\\{([^}]+)\\}", "([^/]+)"); + regex = regex.replaceAll("/+", "/"); // 去除可能由于连续占位符产生的多余斜杠 + regex = "^" + regex + "$"; // 锚定整个字符串的匹配 + + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(actualPath); + + if (matcher.find()) { + // 提取占位符名称和对应的值 + Pattern variablePattern = Pattern.compile("\\{([^}]+)\\}"); + Matcher variableMatcher = variablePattern.matcher(template); + int index = 1; // 匹配值的索引从1开始(0是整个匹配的字符串) + while (variableMatcher.find()) { + String variableName = variableMatcher.group(1); + String variableValue = matcher.group(index++); + variables.put(variableName, variableValue); + } + } + + return variables; + } + private RpcInvokeModeEnum getInvokeMode(Request request) { Collection invokeModel = request.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.singletonList(starterProperties.getInvokeMode().name())); @@ -115,7 +218,7 @@ public class ComplexInvokeClient implements Client { static Response.Body body = new Response.Body() { final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success(HttpStatus.OK.value(), "Send MQ Success", null)) - .getBytes(StandardCharsets.UTF_8)); + .getBytes(UTF_8)); @Override public Integer length() { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java index 235ce890a..57472159b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -49,7 +49,7 @@ class WorkflowEngineStarterInvocationHandler implements InvocationHandler { return dispatch.get(method).invoke(args); } - private static void parseInvokeModelAnnotation(Method method) { + private void parseInvokeModelAnnotation(Method method) { InvokeMode annotation = AnnotationUtils.getAnnotation(method, InvokeMode.class); if (Objects.nonNull(annotation)) { ThreadUtil.set(annotation.value()); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 2d65be7a6..a3c9bee81 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -8,6 +8,7 @@ import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeD import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.api.WorkflowCoreService; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONValidator; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,7 +19,9 @@ import org.springframework.core.env.Environment; import java.lang.reflect.Method; import java.net.ConnectException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -89,9 +92,14 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In try { // 事件处理 RPC 请求, 强制使用同步模式 ThreadUtil.set(SYNC); - // TODO 入参需要根据类型进行转换 - Class parameterType = method.getParameterTypes()[0]; - Object invoke = method.invoke(workflowCoreService, JSON.parseObject((String) dto.getBody(), parameterType)); + Map, Object> parameters = dto.getParameters(); + List parameterValues = new ArrayList<>(parameters.values()); + parameters.forEach((k, v) -> { + if (JSONValidator.from(String.valueOf(v)).validate()) { + + } + }); + Object invoke = method.invoke(workflowCoreService, dto.getParameters()); log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 From 832bc5db3c6e47c788dc135f0b01de1a545b3f20 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 3 Jun 2024 19:06:17 +0800 Subject: [PATCH 053/210] =?UTF-8?q?update(REQ-2516)=20-=20RPC=20=E5=8A=A8?= =?UTF-8?q?=E4=BD=9C=E7=9A=84=20event=EF=BC=8C=E5=9C=A8=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E6=A8=A1=E5=BC=8F=E4=B8=8B=EF=BC=8C=E4=BB=8D?= =?UTF-8?q?=E8=BF=98=E9=9C=80=E8=A6=81=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/WorkflowEngineStarterRpcInvokeDTO.java | 49 +++++++++++++++++-- .../server/controller/web/TestController.java | 23 +++++++++ .../starter/api/WorkflowCoreService.java | 10 +++- .../starter/api/WorkflowCoreService_Gen.java | 3 +- .../feign/ext/ComplexInvokeClient.java | 46 +++++++++++++---- ...rkflowEngineStarterRetryEventListener.java | 27 ++++++---- 6 files changed, 133 insertions(+), 25 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java index 954e386a1..de2b73d0f 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java @@ -1,7 +1,9 @@ package cn.axzo.workflow.common.model.response.mq; +import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; + import java.io.Serializable; -import java.util.Map; +import java.util.List; /** * Starter RPC 调用事件模型 @@ -16,7 +18,7 @@ public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { private String methodName; - private Map, Object> parameters; + private List parameters; public String getClassName() { return className; @@ -34,11 +36,50 @@ public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { this.methodName = methodName; } - public Map, Object> getParameters() { + public List getParameters() { return parameters; } - public void setParameters(Map, Object> parameters) { + public void setParameters(List parameters) { this.parameters = parameters; } + + public static class ParameterType implements Serializable { + private Class parameterType; + private ParameterizedTypeImpl parameterizedType; + private Class annotationClass; + private Object value; + + public Class getParameterType() { + return parameterType; + } + + public void setParameterType(Class parameterType) { + this.parameterType = parameterType; + } + + public ParameterizedTypeImpl getParameterizedType() { + return parameterizedType; + } + + public void setParameterizedType(ParameterizedTypeImpl parameterizedType) { + this.parameterizedType = parameterizedType; + } + + public Class getAnnotationClass() { + return annotationClass; + } + + public void setAnnotationClass(Class annotationClass) { + this.annotationClass = annotationClass; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 85ff8c8c3..cbbbfa669 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.InputStream; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; @@ -219,4 +220,26 @@ public class TestController { workflowCoreService.createVariable(processInstanceId, variable); return CommonResponse.success(null); } + + @GetMapping("/batch/abort") + public CommonResponse test10(@RequestParam(required = false) Boolean sync) { + if (Objects.isNull(sync)) { + throw new RuntimeException("sync 参数不能为 null"); + } + if (Objects.nonNull(sync)) { + if (sync) { + workflowCoreService.sync(); + } else { + workflowCoreService.async(); + } + } + List dtos = new ArrayList<>(); + BpmnProcessInstanceAbortDTO abort = new BpmnProcessInstanceAbortDTO(); + abort.setProcessInstanceId("1"); + abort.setTenantId("2"); + abort.setReason("reason"); + dtos.add(abort); + workflowCoreService.batchAbortProcessInstance(dtos); + return CommonResponse.success(dtos); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index f387f5002..6f507a43b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -2,15 +2,18 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -19,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.annotation.Nullable; import javax.validation.constraints.NotBlank; +import java.util.List; import java.util.Map; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; @@ -54,10 +58,14 @@ public interface WorkflowCoreService { @Nullable @RequestParam(required = false) String tenantId); @Operation(summary = "为指定流程新增变量") - @PostMapping("/api/process/variable/create/{executionId}") + @GetMapping("/api/process/variable/create/{executionId}") void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); + @Operation(summary = "批量中止流程实例") + @DeleteMapping("/api/process/instance/batch/abort") + BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); + default WorkflowCoreService sync() { ThreadUtil.set(SYNC); return this; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java index ac90f8bbb..5782452f1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java @@ -43,6 +43,7 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.annotation.Nullable; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; @@ -171,7 +172,7 @@ public interface WorkflowCoreService_Gen { ) @GetMapping("/api/process/task/batch/find") CommonResponse> findTaskIdByInstanceIdsAndPersonId( - @RequestParam(required = false) @NotNull(message = "流程实例 ID列表 不能为空") List processInstanceIds, + @RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); @Operation( diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index aebf1c95b..9c72a4b93 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -12,6 +12,7 @@ import feign.Client; import feign.MethodMetadata; import feign.Request; import feign.Response; +import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; @@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; +import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -32,16 +34,21 @@ import java.io.Reader; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; @@ -107,14 +114,15 @@ public class ComplexInvokeClient implements Client { event.setClassName(metadata.targetType().getName()); event.setMethodName(metadata.method().getName()); - Map, Object> args = new HashMap<>(); + List args = new ArrayList<>(); event.setParameters(args); buildArgs(request, metadata, args); rpcInvokeEventProducer.send(WORKFLOW_ENGINE_STARTER, event); } - private void buildArgs(Request request, MethodMetadata metadata, Map, Object> args) { + @SneakyThrows + private void buildArgs(Request request, MethodMetadata metadata, List args) { Parameter[] parameters = metadata.method().getParameters(); Class[] parameterTypes = metadata.method().getParameterTypes(); Annotation[][] parameterAnnotations = metadata.method().getParameterAnnotations(); @@ -127,15 +135,37 @@ public class ComplexInvokeClient implements Client { for (int i = 0; i < parameters.length; i++) { // 目前工作流的所有 API,只用了 RequestParam / RequestBody / PathVariable 三个注解,所以这里只处理这三种 Parameter parameter = parameters[i]; - Class parameterType = parameterTypes[i]; + Type parameterType = parameter.getParameterizedType(); Annotation[] annotations = parameterAnnotations[i]; for (Annotation annotation : annotations) { + WorkflowEngineStarterRpcInvokeDTO.ParameterType arg = new WorkflowEngineStarterRpcInvokeDTO.ParameterType(); + if (parameterType instanceof ParameterizedType) { + arg.setParameterizedType((ParameterizedTypeImpl) parameterType); + } else { + arg.setParameterType((Class) parameterType); + } if (annotation instanceof RequestParam) { - args.put(parameterType, parameterType.cast(queries.getOrDefault(parameter.getName(), Collections.emptyList()))); + arg.setAnnotationClass(RequestParam.class); + // RequestParam 支持 Nullable + List values = (List) queries.getOrDefault(parameter.getName(), Collections.emptyList()); + Class aClass = (Class) parameterType; + if (!CollectionUtils.isEmpty(values)) { + if (values.size() > 1) { + arg.setValue(values.stream().map(aClass::cast).collect(Collectors.toSet())); + } else { + arg.setValue(aClass.cast(values.get(0))); + } + } + args.add(arg); } else if (annotation instanceof PathVariable) { - args.put(parameterType, parameterType.cast(pathVariableQueue.poll())); + Class aClass = (Class) parameterType; + arg.setAnnotationClass(PathVariable.class); + arg.setValue(aClass.cast(pathVariableQueue.poll())); + args.add(arg); } else if (annotation instanceof RequestBody) { - args.put(parameterType, new String(body, UTF_8)); + arg.setAnnotationClass(RequestBody.class); + arg.setValue(new String(body, UTF_8)); + args.add(arg); } else { log.warn("annotation is not supported: {}", annotation); } @@ -196,9 +226,7 @@ public class ComplexInvokeClient implements Client { Matcher variableMatcher = variablePattern.matcher(template); int index = 1; // 匹配值的索引从1开始(0是整个匹配的字符串) while (variableMatcher.find()) { - String variableName = variableMatcher.group(1); - String variableValue = matcher.group(index++); - variables.put(variableName, variableValue); + variables.put(variableMatcher.group(1), matcher.group(index++)); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index a3c9bee81..17953e9a4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -8,7 +8,6 @@ import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeD import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.api.WorkflowCoreService; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONValidator; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,10 +15,10 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.RequestBody; import java.lang.reflect.Method; import java.net.ConnectException; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -92,14 +91,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In try { // 事件处理 RPC 请求, 强制使用同步模式 ThreadUtil.set(SYNC); - Map, Object> parameters = dto.getParameters(); - List parameterValues = new ArrayList<>(parameters.values()); - parameters.forEach((k, v) -> { - if (JSONValidator.from(String.valueOf(v)).validate()) { - - } - }); - Object invoke = method.invoke(workflowCoreService, dto.getParameters()); + Object invoke = method.invoke(workflowCoreService, convertToActualArgs(dto.getParameters())); log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 @@ -112,6 +104,21 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In } } + private Object[] convertToActualArgs(List parameters) { + Object[] args = new Object[parameters.size()]; + for (int i = 0; i < parameters.size(); i++) { + WorkflowEngineStarterRpcInvokeDTO.ParameterType parameterType = parameters.get(i); + if (Objects.equals(parameterType.getAnnotationClass(), RequestBody.class)) { + args[i] = (JSON.parseObject(String.valueOf(parameterType.getValue()), + Objects.nonNull(parameterType.getParameterizedType()) ? parameterType.getParameterizedType() : parameterType.getParameterType())); + } else { + args[i] = (parameterType.getParameterType().cast(parameterType.getValue())); + } + + } + return args; + } + private Throwable getRealCause(Throwable error) { while (Objects.nonNull(error.getCause())) { // TODO 如果有必要, 可以在这里对异常进行判断/过滤之类的动作, 目前暂未发现需要处理的场景, From 3b319c0f023ee7ebe7f4bccac677361731c9d721 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 3 Jun 2024 20:24:58 +0800 Subject: [PATCH 054/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=A4=9A=E4=B8=AA=20RPC=20=E5=BC=82=E6=AD=A5=E5=8A=A8?= =?UTF-8?q?=E4=BD=9C=EF=BC=8C=E5=9D=87=E6=88=90=E5=8A=9F=E8=B0=83=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/WorkflowEngineStarterRpcInvokeDTO.java | 47 ++----------------- .../web/bpmn/BpmnProcessTaskController.java | 4 +- .../feign/ext/ComplexInvokeClient.java | 38 ++------------- .../ext/WorkflowEngineStarterDecoder.java | 6 ++- ...rkflowEngineStarterRetryEventListener.java | 30 ++++++++---- 5 files changed, 35 insertions(+), 90 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java index de2b73d0f..d01e38598 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/WorkflowEngineStarterRpcInvokeDTO.java @@ -1,7 +1,5 @@ package cn.axzo.workflow.common.model.response.mq; -import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; - import java.io.Serializable; import java.util.List; @@ -18,7 +16,7 @@ public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { private String methodName; - private List parameters; + private List parameters; public String getClassName() { return className; @@ -36,50 +34,11 @@ public class WorkflowEngineStarterRpcInvokeDTO implements Serializable { this.methodName = methodName; } - public List getParameters() { + public List getParameters() { return parameters; } - public void setParameters(List parameters) { + public void setParameters(List parameters) { this.parameters = parameters; } - - public static class ParameterType implements Serializable { - private Class parameterType; - private ParameterizedTypeImpl parameterizedType; - private Class annotationClass; - private Object value; - - public Class getParameterType() { - return parameterType; - } - - public void setParameterType(Class parameterType) { - this.parameterType = parameterType; - } - - public ParameterizedTypeImpl getParameterizedType() { - return parameterizedType; - } - - public void setParameterizedType(ParameterizedTypeImpl parameterizedType) { - this.parameterizedType = parameterizedType; - } - - public Class getAnnotationClass() { - return annotationClass; - } - - public void setAnnotationClass(Class annotationClass) { - this.annotationClass = annotationClass; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 2d722e5c5..d9cf5cbfd 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -39,7 +39,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Nullable; import javax.annotation.Resource; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -326,7 +326,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/batch/find") @Override - public CommonResponse> findTaskIdByInstanceIdsAndPersonId(@RequestParam @NotNull(message = "流程实例 ID列表 不能为空") List processInstanceIds, + public CommonResponse> findTaskIdByInstanceIdsAndPersonId(@RequestParam @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam @NotBlank(message = "自然人 ID 不能为空") String personId) { return success(bpmnProcessTaskService.findTaskIdByInstanceIdsAndPersonId(processInstanceIds, personId)); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 9c72a4b93..14dc72c2b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; -import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -34,8 +33,6 @@ import java.io.Reader; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; @@ -48,7 +45,6 @@ import java.util.Objects; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; @@ -114,7 +110,7 @@ public class ComplexInvokeClient implements Client { event.setClassName(metadata.targetType().getName()); event.setMethodName(metadata.method().getName()); - List args = new ArrayList<>(); + List args = new ArrayList<>(); event.setParameters(args); buildArgs(request, metadata, args); @@ -122,9 +118,8 @@ public class ComplexInvokeClient implements Client { } @SneakyThrows - private void buildArgs(Request request, MethodMetadata metadata, List args) { + private void buildArgs(Request request, MethodMetadata metadata, List args) { Parameter[] parameters = metadata.method().getParameters(); - Class[] parameterTypes = metadata.method().getParameterTypes(); Annotation[][] parameterAnnotations = metadata.method().getParameterAnnotations(); Map> queries = request.requestTemplate().queries(); byte[] body = request.requestTemplate().body(); @@ -135,39 +130,16 @@ public class ComplexInvokeClient implements Client { for (int i = 0; i < parameters.length; i++) { // 目前工作流的所有 API,只用了 RequestParam / RequestBody / PathVariable 三个注解,所以这里只处理这三种 Parameter parameter = parameters[i]; - Type parameterType = parameter.getParameterizedType(); Annotation[] annotations = parameterAnnotations[i]; for (Annotation annotation : annotations) { - WorkflowEngineStarterRpcInvokeDTO.ParameterType arg = new WorkflowEngineStarterRpcInvokeDTO.ParameterType(); - if (parameterType instanceof ParameterizedType) { - arg.setParameterizedType((ParameterizedTypeImpl) parameterType); - } else { - arg.setParameterType((Class) parameterType); - } if (annotation instanceof RequestParam) { - arg.setAnnotationClass(RequestParam.class); // RequestParam 支持 Nullable List values = (List) queries.getOrDefault(parameter.getName(), Collections.emptyList()); - Class aClass = (Class) parameterType; - if (!CollectionUtils.isEmpty(values)) { - if (values.size() > 1) { - arg.setValue(values.stream().map(aClass::cast).collect(Collectors.toSet())); - } else { - arg.setValue(aClass.cast(values.get(0))); - } - } - args.add(arg); + args.add(JSON.toJSONString(values)); } else if (annotation instanceof PathVariable) { - Class aClass = (Class) parameterType; - arg.setAnnotationClass(PathVariable.class); - arg.setValue(aClass.cast(pathVariableQueue.poll())); - args.add(arg); + args.add(pathVariableQueue.poll()); } else if (annotation instanceof RequestBody) { - arg.setAnnotationClass(RequestBody.class); - arg.setValue(new String(body, UTF_8)); - args.add(arg); - } else { - log.warn("annotation is not supported: {}", annotation); + args.add(new String(body, UTF_8)); } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 373611466..276d9d18a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -57,10 +57,12 @@ final class WorkflowEngineStarterDecoder implements Decoder { * @return */ Object convert(Response response, Type type) throws IOException { + ParameterizedTypeImpl wrappedType; if (type instanceof ParameterizedType) { - return delegate.decode(response, type); + wrappedType = (ParameterizedTypeImpl) type; + } else { + wrappedType = ParameterizedTypeImpl.make(CommonResponse.class, new Type[]{type}, null); } - ParameterizedTypeImpl wrappedType = ParameterizedTypeImpl.make(CommonResponse.class, new Type[]{type}, null); Object decode = delegate.decode(response, wrappedType); if (decode instanceof CommonResponse) { CommonResponse commonResponse = (CommonResponse) decode; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 17953e9a4..da8689e1e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -15,8 +15,12 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.ConnectException; import java.util.HashMap; @@ -91,7 +95,9 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In try { // 事件处理 RPC 请求, 强制使用同步模式 ThreadUtil.set(SYNC); - Object invoke = method.invoke(workflowCoreService, convertToActualArgs(dto.getParameters())); + Object[] args = convertToActualArgs(method, dto.getParameters()); + log.info("event rpc request args: {}", JSON.toJSONString(args)); + Object invoke = method.invoke(workflowCoreService, args); log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 @@ -104,17 +110,23 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In } } - private Object[] convertToActualArgs(List parameters) { + private Object[] convertToActualArgs(Method method, List parameters) { Object[] args = new Object[parameters.size()]; + Class[] parameterTypes = method.getParameterTypes(); + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < parameters.size(); i++) { - WorkflowEngineStarterRpcInvokeDTO.ParameterType parameterType = parameters.get(i); - if (Objects.equals(parameterType.getAnnotationClass(), RequestBody.class)) { - args[i] = (JSON.parseObject(String.valueOf(parameterType.getValue()), - Objects.nonNull(parameterType.getParameterizedType()) ? parameterType.getParameterizedType() : parameterType.getParameterType())); - } else { - args[i] = (parameterType.getParameterType().cast(parameterType.getValue())); + Class parameterType = parameterTypes[i]; + Annotation[] annotations = parameterAnnotations[i]; + for (Annotation annotation : annotations) { + if (annotation instanceof RequestParam) { + List arg = JSON.parseObject(parameters.get(i), List.class); + args[i] = Objects.equals(parameterType, List.class) ? arg : CollectionUtils.isEmpty(arg) ? null : arg.get(0); + } else if (annotation instanceof PathVariable) { + args[i] = parameters.get(i); + } else if (annotation instanceof RequestBody) { + args[i] = JSON.parseObject(parameters.get(i), parameterType); + } } - } return args; } From c7c6db476552cf26e87e2757d4059a6500816b38 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 3 Jun 2024 20:38:46 +0800 Subject: [PATCH 055/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=B8=9A=E5=8A=A1=E9=9C=80=E5=AE=9E=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/MessageNotificationListener.java | 2 +- .../listener/ProcessActivityListener.java | 6 ++++++ .../listener/ProcessInstanceListener.java | 2 ++ .../starter/listener/ProcessListener.java | 18 ------------------ .../starter/listener/ProcessTaskListener.java | 4 ++++ 5 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java index b0bcfaa81..b78bbb2c2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java @@ -4,7 +4,7 @@ import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import org.springframework.core.Ordered; /** - * 消息事件对应mq消息,按照ordered由小到大顺序执行 + * 引擎广播发送消息的事件, 业务一般无需实现,该事件由引擎的中继服务去处理待办相关动作的。 * * @author wangli * @since 2024/5/27 16:25 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java index f4c9f77a3..b8823a95d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java @@ -4,6 +4,12 @@ import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import org.springframework.core.Ordered; /** + * 流程节点相关事件 + *

+ * 节点代表“流程配置”中的一个“审批节点”或“业务节点”,流程配置请按照以下路径去查看 + *

+ *  OMS -> 审批流程 -> 审批配置台 -> 流程配置
+ * 
* @author wangli * @since 2024/5/27 16:25 */ diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java index 145f422d9..d05d0bb4c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java @@ -4,6 +4,8 @@ import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import org.springframework.core.Ordered; /** + * 流程实例相关事件 + * * @author wangli * @since 2024/5/27 16:20 */ diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java deleted file mode 100644 index 92aaa9c83..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessListener.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.axzo.workflow.starter.listener; - -import org.springframework.core.Ordered; - -/** - * TODO - * - * @author wangli - * @since 2024/5/27 16:26 - */ -public interface ProcessListener extends Ordered { - /** - * 入参来源于配置 - * - * @param auto - */ - void ack(Boolean auto); -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java index 9e7e00dc8..cd6720cdd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java @@ -4,6 +4,10 @@ import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import org.springframework.core.Ordered; /** + * 审批任务相关事件 + *

+ * 一个节点(Activity)可以包含 0个或多个任务(Task),它们两者是包含关系 + * * @author wangli * @since 2024/5/27 16:21 */ From dde7e35d455cce00f672c629d3b79300b6eac441 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 3 Jun 2024 20:51:44 +0800 Subject: [PATCH 056/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=B8=9A=E5=8A=A1=E9=9C=80=E5=AE=9E=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/ProcessInstanceListener.java | 44 +++++++++++-------- .../consumer/AbstractWorkflowListener.java | 7 +-- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java index d05d0bb4c..6b848e7bc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java @@ -1,5 +1,7 @@ package cn.axzo.workflow.starter.listener; +import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import org.springframework.core.Ordered; @@ -16,42 +18,48 @@ public interface ProcessInstanceListener extends Ordered { * * @param processInstanceDTO */ - void onCreated(ProcessInstanceDTO processInstanceDTO); + void onCreated(ProcessInstanceDTO instanceDTO); /** * 流程实例开始运行后回调 * * @param processInstanceDTO */ - void onStarted(ProcessInstanceDTO processInstanceDTO); + void onStarted(ProcessInstanceDTO instanceDTO); /** - * 流程实例被撤回后回调 + * 流程实例运行完成(通过)后回调 + *

+ * 注意: 该接口表明流程已经走完正向逻辑,正向逻辑比如:通过、同意等 * - * @param processInstanceDTO + * @param instanceDTO */ - void onCancelled(ProcessInstanceDTO processInstanceDTO); + void onCompleted(ProcessInstanceDTO instanceDTO); /** - * 流程实例被驳回后回调 + * 流程实例被“撤回”后回调 + *

+ * 撤回只有发起人能触发 * - * @param processInstanceDTO + * @param instanceDTO */ - void onRejected(ProcessInstanceDTO processInstanceDTO); + void onCancelled(ProcessInstanceDTO instanceDTO); + + /** + * 流程实例被“驳回”后回调 + *

+ * 审批过程中,有一个审批人或者有节点配置的是“自动驳回”,都能触发该事件。 + * + * @param instanceDTO + */ + void onRejected(ProcessInstanceDTO instanceDTO); /** * 流程实例被中止后回调 - * - * @param event - */ - void onAborted(ProcessInstanceDTO event); - - /** - * 流程实例运行完成后回调 *

- * 注意: 完成只是说明流程实例已停止运行 + * 一般由接入方主动触发,比如调用了 {@link ProcessInstanceApi#abortProcessInstance(BpmnProcessInstanceAbortDTO)} 方法等 * - * @param event + * @param instanceDTO */ - void onCompleted(ProcessInstanceDTO event); + void onAborted(ProcessInstanceDTO instanceDTO); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index 37ca7510b..0159543bb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -5,7 +5,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; -import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -20,10 +20,7 @@ public abstract class AbstractWorkflowListener implements Wor protected List getCustomListeners() { - List list = instanceListenersProvider.getIfAvailable(); - if (list == null) { - list = new ArrayList(); - } + List list = instanceListenersProvider.getIfAvailable(Collections::emptyList); return list.stream().sorted(Comparator.comparingInt(Ordered::getOrder)).collect(Collectors.toList()); } From b4b161635d19003a48e51fd5b0d9145d12ecbbc6 Mon Sep 17 00:00:00 2001 From: wangli Date: Mon, 3 Jun 2024 22:04:51 +0800 Subject: [PATCH 057/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20Starter=20=E4=B8=AD=20Bean=20=E7=9A=84=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=96=B9=E5=BC=8F,=20=E4=B8=8D=E4=BD=BF=E7=94=A8=20Sp?= =?UTF-8?q?ringBean=20=E6=B3=A8=E8=A7=A3,=20=E9=81=BF=E5=85=8D=E5=9B=A0?= =?UTF-8?q?=E4=B8=BA=E5=8C=85=E6=89=AB=E6=8F=8F=E9=97=AE=E9=A2=98=E5=BC=95?= =?UTF-8?q?=E8=B5=B7=20Bean=20=E7=BC=BA=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 28 +++++++++++++++-- .../consumer/InnerActivityEventListener.java | 2 -- .../consumer/InnerInstanceEventListener.java | 2 -- .../consumer/InnerNoticeEventListener.java | 2 -- .../consumer/InnerTaskEventListener.java | 2 -- .../starter/mq/execute/ListenerExecutor.java | 26 ++++++++++++++-- .../mq/execute/ListenerExecutorImpl.java | 31 ------------------- .../execute/interceptor/LogInterceptor.java | 6 ++-- 8 files changed, 53 insertions(+), 46 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 2142b3088..8189a70d1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -2,8 +2,12 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNoticeEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutorImpl; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; import cn.axzo.workflow.starter.mq.execute.interceptor.FailBackInterceptor; @@ -45,7 +49,27 @@ public class WorkflowEngineStarterAutoConfiguration { // additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); // } interceptors.add(new ExecutorInvoker()); - return new ListenerExecutorImpl(interceptors); + return new ListenerExecutor(interceptors); + } + + @Bean + public WorkflowListener innerProcessEventListener() { + return new InnerInstanceEventListener(); + } + + @Bean + public WorkflowListener innerActivityEventListener() { + return new InnerActivityEventListener(); + } + + @Bean + public WorkflowListener innerTaskEventListener() { + return new InnerTaskEventListener(); + } + + @Bean + public WorkflowListener innerNotificationEventListener() { + return new InnerNoticeEventListener(); } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 62a539ca4..788267406 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -9,7 +9,6 @@ import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.List; @@ -19,7 +18,6 @@ import java.util.function.Consumer; * @author wangli * @since 2024/5/21 15:51 */ -@Component public class InnerActivityEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index 8150efead..ecabfd70f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -9,7 +9,6 @@ import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.List; @@ -26,7 +25,6 @@ import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INS * @author wangli * @since 2024/5/21 15:51 */ -@Component public class InnerInstanceEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java index 634a81777..b25971257 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java @@ -9,7 +9,6 @@ import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.List; @@ -19,7 +18,6 @@ import java.util.function.Consumer; * @author wangli * @since 2024/5/21 15:53 */ -@Component public class InnerNoticeEventListener extends AbstractWorkflowListener { private final static Logger log = LoggerFactory.getLogger(InnerNoticeEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 7b8d37665..9d2eaed5d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -9,7 +9,6 @@ import com.alibaba.fastjson.JSON; import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.List; @@ -24,7 +23,6 @@ import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_DE * @author wangli * @since 2024/5/21 15:51 */ -@Component public class InnerTaskEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerTaskEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java index b7de37988..e5a055b32 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java @@ -1,8 +1,30 @@ package cn.axzo.workflow.starter.mq.execute; +import cn.axzo.framework.domain.ServiceException; +import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; + +import java.util.List; import java.util.function.Consumer; -public interface ListenerExecutor { +public final class ListenerExecutor { - void execute(Consumer command, T t); + private final ExecuteInterceptor firstExecuteInterceptor; + + public ListenerExecutor(List chain) { + this.firstExecuteInterceptor = initInterceptorChain(chain); + } + + public void execute(Consumer command, T t) { + firstExecuteInterceptor.execute(this, command, t); + } + + private ExecuteInterceptor initInterceptorChain(List chain) { + if (chain == null || chain.isEmpty()) { + throw new ServiceException("invalid command interceptor chain configuration: " + chain); + } + for (int i = 0; i < chain.size() - 1; i++) { + chain.get(i).setNext(chain.get(i + 1)); + } + return chain.get(0); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java deleted file mode 100644 index ec177f726..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutorImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.axzo.workflow.starter.mq.execute; - -import cn.axzo.framework.domain.ServiceException; -import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; - -import java.util.List; -import java.util.function.Consumer; - -public final class ListenerExecutorImpl implements ListenerExecutor { - - private final ExecuteInterceptor firstExecuteInterceptor; - - public ListenerExecutorImpl(List chain) { - this.firstExecuteInterceptor = initInterceptorChain(chain); - } - - @Override - public void execute(Consumer command, T t) { - firstExecuteInterceptor.execute(this, command, t); - } - - private ExecuteInterceptor initInterceptorChain(List chain) { - if (chain == null || chain.isEmpty()) { - throw new ServiceException("invalid command interceptor chain configuration: " + chain); - } - for (int i = 0; i < chain.size() - 1; i++) { - chain.get(i).setNext(chain.get(i + 1)); - } - return chain.get(0); - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java index 4e4649870..d4d677306 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java @@ -8,18 +8,18 @@ import org.springframework.util.StopWatch; import java.util.function.Consumer; public final class LogInterceptor extends AbstractListenerInterceptor { - private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class); + private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class); @Override public void execute(ListenerExecutor executor, Consumer consumer, T t) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); - LOGGER.debug("--- starting {} ----", executor.getClass().getSimpleName()); + log.debug("--- starting {} ----", executor.getClass().getSimpleName()); try { getNext().execute(executor, consumer, t); } finally { stopWatch.stop(); - LOGGER.debug("--- {} finished ,timeCost:{} ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); + log.debug("--- {} finished ,timeCost:{} ms ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); } } } From 7c2322f5328b31b21ff97c38aad7c9368bade8c3 Mon Sep 17 00:00:00 2001 From: wangli Date: Mon, 3 Jun 2024 22:08:13 +0800 Subject: [PATCH 058/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E7=B1=BB=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/WorkflowEngineStarterAutoConfiguration.java | 4 ++-- ...EventListener.java => InnerNotificationEventListener.java} | 4 ++-- .../consumer/WorkflowEngineBroadcastEventListener.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/{InnerNoticeEventListener.java => InnerNotificationEventListener.java} (97%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 8189a70d1..663443abb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -4,7 +4,7 @@ import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; -import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNoticeEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; @@ -69,7 +69,7 @@ public class WorkflowEngineStarterAutoConfiguration { @Bean public WorkflowListener innerNotificationEventListener() { - return new InnerNoticeEventListener(); + return new InnerNotificationEventListener(); } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java similarity index 97% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java index b25971257..b791dd359 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNoticeEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java @@ -18,8 +18,8 @@ import java.util.function.Consumer; * @author wangli * @since 2024/5/21 15:53 */ -public class InnerNoticeEventListener extends AbstractWorkflowListener { - private final static Logger log = LoggerFactory.getLogger(InnerNoticeEventListener.class); +public class InnerNotificationEventListener extends AbstractWorkflowListener { + private final static Logger log = LoggerFactory.getLogger(InnerNotificationEventListener.class); public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( ProcessMessagePushEventEnum.PROCESS_PUSH_NOTICE.getEventCode(), ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING.getEventCode(), diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 33a612fe8..2e2c92bd8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -43,7 +43,7 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi public void afterPropertiesSet() { eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerNoticeEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerNotificationEventListener.SUPPORTED_EVENT_CODES, this); eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); } } From 1c5bafa55b0c2e3b70941a8db477b53152bce116 Mon Sep 17 00:00:00 2001 From: wangli Date: Mon, 3 Jun 2024 22:55:58 +0800 Subject: [PATCH 059/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=BE=9B=E4=B8=9A=E5=8A=A1=E5=AE=9E=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86=E5=99=A8=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?,=20=E4=BB=A5=E5=8F=8A=E5=86=85=E9=83=A8=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 29 ++++-- ...a => MessageNotificationEventHandler.java} | 2 +- ....java => ProcessActivityEventHandler.java} | 2 +- ....java => ProcessInstanceEventHandler.java} | 2 +- ...ener.java => ProcessTaskEventHandler.java} | 2 +- .../consumer/AbstractWorkflowListener.java | 26 +++-- .../consumer/InnerActivityEventListener.java | 35 ++++--- .../consumer/InnerInstanceEventListener.java | 44 ++++----- .../InnerNotificationEventListener.java | 95 ++++--------------- .../consumer/InnerTaskEventListener.java | 40 ++++---- .../WorkflowEngineBroadcastEventListener.java | 15 ++- .../broadcast/consumer/WorkflowListener.java | 3 +- 12 files changed, 138 insertions(+), 157 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/{MessageNotificationListener.java => MessageNotificationEventHandler.java} (94%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/{ProcessActivityListener.java => ProcessActivityEventHandler.java} (94%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/{ProcessInstanceListener.java => ProcessInstanceEventHandler.java} (96%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/{ProcessTaskListener.java => ProcessTaskEventHandler.java} (94%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 663443abb..920bbae0d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -2,6 +2,10 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; +import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; +import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; +import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; +import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; @@ -16,6 +20,7 @@ import cn.axzo.workflow.starter.mq.execute.interceptor.FailOverInterceptor; import cn.axzo.workflow.starter.mq.execute.interceptor.LogInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; @@ -40,8 +45,8 @@ public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); @Bean - public ListenerExecutor initListenerExecutor(WorkflowEngineStarterProperties starterProperties, - List additionalInterceptors) { + public ListenerExecutor listenerExecutor(WorkflowEngineStarterProperties starterProperties, + List additionalInterceptors) { List interceptors = new ArrayList<>(); interceptors.add(new LogInterceptor()); interceptors.add(getFailInterceptor(starterProperties)); @@ -53,23 +58,27 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean - public WorkflowListener innerProcessEventListener() { - return new InnerInstanceEventListener(); + public WorkflowListener innerProcessEventListener(ListenerExecutor executor, + ObjectProvider> provider) { + return new InnerInstanceEventListener(executor, provider); } @Bean - public WorkflowListener innerActivityEventListener() { - return new InnerActivityEventListener(); + public WorkflowListener innerActivityEventListener(ListenerExecutor executor, + ObjectProvider> provider) { + return new InnerActivityEventListener(executor, provider); } @Bean - public WorkflowListener innerTaskEventListener() { - return new InnerTaskEventListener(); + public WorkflowListener innerTaskEventListener(ListenerExecutor executor, + ObjectProvider> provider) { + return new InnerTaskEventListener(executor, provider); } @Bean - public WorkflowListener innerNotificationEventListener() { - return new InnerNotificationEventListener(); + public WorkflowListener innerNotificationEventListener(ListenerExecutor executor, + ObjectProvider> provider) { + return new InnerNotificationEventListener(executor, provider); } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationEventHandler.java similarity index 94% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationEventHandler.java index b78bbb2c2..03ffa611d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationEventHandler.java @@ -9,7 +9,7 @@ import org.springframework.core.Ordered; * @author wangli * @since 2024/5/27 16:25 */ -public interface MessageNotificationListener extends Ordered { +public interface MessageNotificationEventHandler extends Ordered { /** * 站内信推送 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityEventHandler.java similarity index 94% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityEventHandler.java index b8823a95d..5769d4437 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityEventHandler.java @@ -13,7 +13,7 @@ import org.springframework.core.Ordered; * @author wangli * @since 2024/5/27 16:25 */ -public interface ProcessActivityListener extends Ordered { +public interface ProcessActivityEventHandler extends Ordered { /** * 节点已启动 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceEventHandler.java similarity index 96% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceEventHandler.java index 6b848e7bc..b969dac49 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceEventHandler.java @@ -11,7 +11,7 @@ import org.springframework.core.Ordered; * @author wangli * @since 2024/5/27 16:20 */ -public interface ProcessInstanceListener extends Ordered { +public interface ProcessInstanceEventHandler extends Ordered { /** * 流程实例创建成功后回调 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskEventHandler.java similarity index 94% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskEventHandler.java index cd6720cdd..8aa906478 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskEventHandler.java @@ -11,7 +11,7 @@ import org.springframework.core.Ordered; * @author wangli * @since 2024/5/27 16:21 */ -public interface ProcessTaskListener extends Ordered { +public interface ProcessTaskEventHandler extends Ordered { /** * 用户任务已指派审核人 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index 0159543bb..dab01ef1d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -1,8 +1,8 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; +import cn.axzo.framework.rocketmq.Event; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; import java.util.Collections; @@ -12,19 +12,31 @@ import java.util.stream.Collectors; public abstract class AbstractWorkflowListener implements WorkflowListener { - @Autowired - private ObjectProvider> instanceListenersProvider; + private final ObjectProvider> listenerProvider; - @Autowired - private ListenerExecutor listenerExecutor; + private final ListenerExecutor listenerExecutor; + + public AbstractWorkflowListener(ListenerExecutor listenerExecutor, ObjectProvider> provider) { + this.listenerExecutor = listenerExecutor; + this.listenerProvider = provider; + } protected List getCustomListeners() { - List list = instanceListenersProvider.getIfAvailable(Collections::emptyList); - return list.stream().sorted(Comparator.comparingInt(Ordered::getOrder)).collect(Collectors.toList()); + return listenerProvider.getIfAvailable(Collections::emptyList) + .stream() + .sorted(Comparator.comparingInt(Ordered::getOrder)) + .collect(Collectors.toList()); } protected ListenerExecutor getListenerExecutor() { return listenerExecutor; } + + @Override + public boolean support(Event event) { + return getSupportEventCodes().contains(event.getEventCode()); + } + + protected abstract List getSupportEventCodes(); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 788267406..57de1fa40 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -4,36 +4,42 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; -import cn.axzo.workflow.starter.listener.ProcessActivityListener; +import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; -import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; /** * @author wangli * @since 2024/5/21 15:51 */ -public class InnerActivityEventListener extends AbstractWorkflowListener { +public class InnerActivityEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); - public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( - ProcessActivityEventEnum.PROCESS_ACTIVITY_START.getEventCode(), - ProcessActivityEventEnum.PROCESS_ACTIVITY_WAIT_ASSIGNEE.getEventCode(), - ProcessActivityEventEnum.PROCESS_ACTIVITY_TAKE.getEventCode(), - ProcessActivityEventEnum.PROCESS_ACTIVITY_END.getEventCode() - ); + + public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> + Arrays.stream(ProcessActivityEventEnum.values()).map(ProcessActivityEventEnum::getEventCode) + .collect(Collectors.toList()); + + public InnerActivityEventListener(ListenerExecutor executor, ObjectProvider> provider) { + super(executor, provider); + } @Override - public void handEvent(Event event, EventConsumer.Context context) { - List activityListeners = getCustomListeners(); + public void handleEvent(Event event, EventConsumer.Context context) { + List activityListeners = getCustomListeners(); if (!CollectionUtils.isEmpty(activityListeners)) { ProcessActivityDTO activityDTO = JSON.parseObject(event.getData().toString(), ProcessActivityDTO.class); ProcessActivityEventEnum type = activityDTO.getType(); - for (ProcessActivityListener activityListener : activityListeners) { + for (ProcessActivityEventHandler activityListener : activityListeners) { Consumer consumer = null; switch (type) { case PROCESS_ACTIVITY_START: @@ -57,7 +63,8 @@ public class InnerActivityEventListener extends AbstractWorkflowListener getSupportEventCodes() { + return SUPPORTED_EVENT_CODES_SUPPLIER.get(); } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index ecabfd70f..e93b9debc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -4,45 +4,42 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; -import cn.axzo.workflow.starter.listener.ProcessInstanceListener; +import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; -import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; - -import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_ABORTED; -import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_CANCELLED; -import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_COMPLETED; -import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_CREATED; -import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_REJECTED; -import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_STARTED; +import java.util.function.Supplier; +import java.util.stream.Collectors; /** * @author wangli * @since 2024/5/21 15:51 */ -public class InnerInstanceEventListener extends AbstractWorkflowListener { +public class InnerInstanceEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); - public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( - PROCESS_INSTANCE_CREATED.getEventCode(), - PROCESS_INSTANCE_STARTED.getEventCode(), - PROCESS_INSTANCE_CANCELLED.getEventCode(), - PROCESS_INSTANCE_REJECTED.getEventCode(), - PROCESS_INSTANCE_ABORTED.getEventCode(), - PROCESS_INSTANCE_COMPLETED.getEventCode() - ); + + public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> + Arrays.stream(ProcessInstanceEventEnum.values()).map(ProcessInstanceEventEnum::getEventCode) + .collect(Collectors.toList()); + + public InnerInstanceEventListener(ListenerExecutor listenerExecutor, ObjectProvider> provider) { + super(listenerExecutor, provider); + } @Override - public void handEvent(Event event, EventConsumer.Context context) { - List instanceListeners = getCustomListeners(); + public void handleEvent(Event event, EventConsumer.Context context) { + List instanceListeners = getCustomListeners(); if (!CollectionUtils.isEmpty(instanceListeners)) { ProcessInstanceDTO instanceDTO = JSON.parseObject(event.getData().toString(), ProcessInstanceDTO.class); ProcessInstanceEventEnum type = instanceDTO.getType(); - for (ProcessInstanceListener instanceListener : instanceListeners) { + for (ProcessInstanceEventHandler instanceListener : instanceListeners) { Consumer consumer = null; switch (type) { case PROCESS_INSTANCE_CREATED: @@ -72,7 +69,8 @@ public class InnerInstanceEventListener extends AbstractWorkflowListener getSupportEventCodes() { + return SUPPORTED_EVENT_CODES_SUPPLIER.get(); } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java index b791dd359..e6ef6d4fb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java @@ -2,41 +2,45 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; -import cn.axzo.workflow.starter.listener.MessageNotificationListener; +import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; -import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; /** * @author wangli * @since 2024/5/21 15:53 */ -public class InnerNotificationEventListener extends AbstractWorkflowListener { +public class InnerNotificationEventListener extends AbstractWorkflowListener { private final static Logger log = LoggerFactory.getLogger(InnerNotificationEventListener.class); - public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( - ProcessMessagePushEventEnum.PROCESS_PUSH_NOTICE.getEventCode(), - ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING.getEventCode(), - ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING_COMPLETE.getEventCode(), - ProcessMessagePushEventEnum.PROCESS_PUSH_PENDING_ROLLBACK.getEventCode(), - ProcessMessagePushEventEnum.PROCESS_CARBON_COPY.getEventCode(), - ProcessMessagePushEventEnum.PROCESS_CARBON_COPY_COMPLETE.getEventCode(), - ProcessMessagePushEventEnum.PROCESS_PUSH_SMS.getEventCode() - ); + + public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> + Arrays.stream(ProcessInstanceEventEnum.values()).map(ProcessInstanceEventEnum::getEventCode) + .collect(Collectors.toList()); + + public InnerNotificationEventListener(ListenerExecutor executor, ObjectProvider> provider) { + super(executor, provider); + } @Override - public void handEvent(Event event, EventConsumer.Context context) { - List instanceListeners = getCustomListeners(); + public void handleEvent(Event event, EventConsumer.Context context) { + List instanceListeners = getCustomListeners(); if (!CollectionUtils.isEmpty(instanceListeners)) { MessagePushDTO instanceDTO = JSON.parseObject(event.getData().toString(), MessagePushDTO.class); ProcessMessagePushEventEnum type = instanceDTO.getType(); - for (MessageNotificationListener noticeListener : instanceListeners) { + for (MessageNotificationEventHandler noticeListener : instanceListeners) { Consumer consumer = null; switch (type) { case PROCESS_PUSH_NOTICE: @@ -69,66 +73,9 @@ public class InnerNotificationEventListener extends AbstractWorkflowListener getSupportEventCodes() { + return SUPPORTED_EVENT_CODES_SUPPLIER.get(); } - public static void main(String[] args) { - MessageNotificationListener listener = new MessageNotificationListener() { - @Override - public int getOrder() { - return 0; - } - @Override - public void pushNotice(MessagePushDTO messagePushDTO) { - } - - @Override - public void pushPending(MessagePushDTO messagePushDTO) { - - } - - @Override - public void completePending(MessagePushDTO messagePushDTO) { - - } - - @Override - public void rollbackPending(MessagePushDTO messagePushDTO) { - - } - - @Override - public void carbonCopy(MessagePushDTO messagePushDTO) { - - } - - @Override - public void carbonCopyComplete(MessagePushDTO messagePushDTO) { - - } - - @Override - public void pushSms(MessagePushDTO messagePushDTO) { - - } - - public int hashCode() { - return super.hashCode(); - } - }; - - try { - // 最后业务节点的 started 事件,业务再做一个事情, - listener.hashCode(); - - // trigger 最后一个节点, - log.error(""); - } catch (Exception e) { - // 这个地方应该配置项:业务需要阻塞,忽略 - throw new RuntimeException(e); - } - - } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 9d2eaed5d..3dda9fa20 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -4,41 +4,42 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; -import cn.axzo.workflow.starter.listener.ProcessTaskListener; +import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; +import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; -import com.google.common.collect.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.CollectionUtils; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; - -import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED; -import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_COMPLETED; -import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_CREATED; -import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_DELETED; +import java.util.function.Supplier; +import java.util.stream.Collectors; /** * @author wangli * @since 2024/5/21 15:51 */ -public class InnerTaskEventListener extends AbstractWorkflowListener { +public class InnerTaskEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerTaskEventListener.class); - public final static List SUPPORTED_EVENT_CODES = ImmutableList.of( - PROCESS_TASK_CREATED.getEventCode(), - PROCESS_TASK_ASSIGNED.getEventCode(), - PROCESS_TASK_COMPLETED.getEventCode(), - PROCESS_TASK_DELETED.getEventCode() - ); + + public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> + Arrays.stream(ProcessTaskEventEnum.values()).map(ProcessTaskEventEnum::getEventCode) + .collect(Collectors.toList()); + + public InnerTaskEventListener(ListenerExecutor executor, ObjectProvider> provider) { + super(executor, provider); + } @Override - public void handEvent(Event event, EventConsumer.Context context) { - List taskListeners = getCustomListeners(); + public void handleEvent(Event event, EventConsumer.Context context) { + List taskListeners = getCustomListeners(); if (!CollectionUtils.isEmpty(taskListeners)) { ProcessTaskDTO taskDTO = JSON.parseObject(event.getData().toString(), ProcessTaskDTO.class); ProcessTaskEventEnum type = taskDTO.getType(); - for (ProcessTaskListener taskListener : taskListeners) { + for (ProcessTaskEventHandler taskListener : taskListeners) { Consumer consumer = null; switch (type) { case PROCESS_TASK_CREATED: @@ -62,7 +63,8 @@ public class InnerTaskEventListener extends AbstractWorkflowListener getSupportEventCodes() { + return SUPPORTED_EVENT_CODES_SUPPLIER.get(); } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 2e2c92bd8..6b7ddcbac 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.util.CollectionUtils; import java.util.List; +import java.util.Objects; /** * 流程引擎服务广播的事件监听器 @@ -32,18 +33,22 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi log.warn("no workflow listener to handle event: {}", event); return; } + if (Objects.isNull(event) || Objects.isNull(event.getEventCode())) { + log.warn("illegal event code: {}", event); + return; + } for (WorkflowListener workflowListener : workflowListeners) { if (workflowListener.support(event)) { - workflowListener.handEvent(event, context); + workflowListener.handleEvent(event, context); } } } @Override public void afterPropertiesSet() { - eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerNotificationEventListener.SUPPORTED_EVENT_CODES, this); - eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES, this); + eventConsumer.registerHandlers(InnerActivityEventListener.SUPPORTED_EVENT_CODES_SUPPLIER.get(), this); + eventConsumer.registerHandlers(InnerInstanceEventListener.SUPPORTED_EVENT_CODES_SUPPLIER.get(), this); + eventConsumer.registerHandlers(InnerNotificationEventListener.SUPPORTED_EVENT_CODES_SUPPLIER.get(), this); + eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES_SUPPLIER.get(), this); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java index 4f09cb561..f37a73fd0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java @@ -5,7 +5,8 @@ import cn.axzo.framework.rocketmq.EventConsumer; public interface WorkflowListener { - void handEvent(Event event, EventConsumer.Context context); + void handleEvent(Event event, EventConsumer.Context context); boolean support(Event event); } + From 1eda68894495a330e32b6197fc6a5e96ff958ba1 Mon Sep 17 00:00:00 2001 From: wangli Date: Mon, 3 Jun 2024 23:00:17 +0800 Subject: [PATCH 060/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20RPC=20=E5=8A=A8=E4=BD=9C=E5=8F=91=E9=80=81=20MQ=20?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E8=B7=AF=E7=94=B1=E9=94=AE=E4=B8=BA=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E5=BA=94=E7=94=A8=E5=90=8D,=20=E4=BB=8E=E8=80=8C?= =?UTF-8?q?=E5=B0=BD=E9=87=8F=E4=BF=9D=E8=AF=81=E5=8F=91=E9=80=81=E5=88=B0?= =?UTF-8?q?=E7=9A=84=E6=98=AF=E5=90=8C=E4=B8=80=E4=B8=AA=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/mq/retry/producer/RpcInvokeEventProducer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index d319ec170..3c341ee67 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -30,7 +30,7 @@ public class RpcInvokeEventProducer { */ public void send(WorkflowEngineEventEnum eventEnum, WorkflowEngineStarterRpcInvokeDTO data) { workflowEngineClientEventProducer.send(Event.builder() - .shardingKey(data.getMethodName()) + .shardingKey(currentApplicationName) .eventCode(eventEnum.getEventCode(currentApplicationName)) .targetId(data.getMethodName()) .targetType(eventEnum.getTag()) From cd752dc4290a10eb2e08a1b123a2d8b0df4021db Mon Sep 17 00:00:00 2001 From: wangli Date: Mon, 3 Jun 2024 23:02:11 +0800 Subject: [PATCH 061/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20TODO=20=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/WorkflowEngineStarterFeignConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 5b57303bc..dbbbd4d54 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -65,6 +65,7 @@ public class WorkflowEngineStarterFeignConfiguration { template.header(HEADER_HTTP_CLIENT, HEADER_HTTP_CLIENT_VALUE); template.header(HEADER_API_VERSION, serviceVersion); } + // TODO 还需要添加链路追踪相关信息 }; } From f70ee0a1d0d8c94f8c61174a8e3828ed09befac6 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 10:50:39 +0800 Subject: [PATCH 062/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=B8=80=E4=BA=9B=E9=BB=98=E8=AE=A4=20Bean=20?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E5=86=8C=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...lowEngineStarterRocketMQConfiguration.java | 4 ++-- .../consumer/AbstractWorkflowListener.java | 2 +- .../WorkflowEngineBroadcastEventListener.java | 21 ++++++++++++------- .../broadcast/consumer/WorkflowListener.java | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index a5c7f785f..a0bfdc8a4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -98,8 +98,8 @@ public class WorkflowEngineStarterRocketMQConfiguration { @Bean public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, - ObjectProvider> listeners) { - return new WorkflowEngineBroadcastEventListener(eventConsumer, listeners.getIfAvailable()); + ObjectProvider> listenerProvider) { + return new WorkflowEngineBroadcastEventListener(eventConsumer, listenerProvider); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index dab01ef1d..0e406c967 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -34,7 +34,7 @@ public abstract class AbstractWorkflowListener implements Wor } @Override - public boolean support(Event event) { + public boolean dispatch(Event event) { return getSupportEventCodes().contains(event.getEventCode()); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 6b7ddcbac..fcd300b6a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -6,8 +6,10 @@ import cn.axzo.framework.rocketmq.EventHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.CollectionUtils; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -20,25 +22,28 @@ import java.util.Objects; public class WorkflowEngineBroadcastEventListener implements EventHandler, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastEventListener.class); private final EventConsumer eventConsumer; - private final List workflowListeners; + private final ObjectProvider> workflowListenersProvider; - public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, List workflowListeners) { + public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, ObjectProvider> workflowListenersProvider) { this.eventConsumer = eventConsumer; - this.workflowListeners = workflowListeners; + this.workflowListenersProvider = workflowListenersProvider; } @Override public void onEvent(Event event, EventConsumer.Context context) { - if (CollectionUtils.isEmpty(workflowListeners)) { - log.warn("no workflow listener to handle event: {}", event); - return; - } if (Objects.isNull(event) || Objects.isNull(event.getEventCode())) { log.warn("illegal event code: {}", event); return; } + + List workflowListeners = workflowListenersProvider.getIfAvailable(Collections::emptyList); + if (CollectionUtils.isEmpty(workflowListeners)) { + log.warn("no business listeners implementation found, please check @Component annotation"); + return; + } + for (WorkflowListener workflowListener : workflowListeners) { - if (workflowListener.support(event)) { + if (workflowListener.dispatch(event)) { workflowListener.handleEvent(event, context); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java index f37a73fd0..19fcfb336 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowListener.java @@ -7,6 +7,6 @@ public interface WorkflowListener { void handleEvent(Event event, EventConsumer.Context context); - boolean support(Event event); + boolean dispatch(Event event); } From 53b6b49641d466070820ade1190313dc025528cc Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 16:03:31 +0800 Subject: [PATCH 063/210] =?UTF-8?q?update(REQ-2324)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=BC=95=E6=93=8E=E5=B9=BF=E6=92=AD=E7=9A=84=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E8=BF=87=E6=BB=A4=EF=BC=8C=20=E7=9B=AE?= =?UTF-8?q?=E5=89=8D=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=90=8D=E5=92=8CprocessDefinitionKeys=20=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 4 + .../core/mq/CustomRocketMQEventProducer.java | 7 +- ...adcastListenerConfigurationProperties.java | 117 ++++++++++++++++++ ...orkflowEngineStarterAutoConfiguration.java | 10 +- .../WorkflowEngineStarterProperties.java | 76 ++---------- ...lowEngineStarterRocketMQConfiguration.java | 96 +++++++++++--- .../feign/ext/ComplexInvokeClient.java | 9 +- ...rkflowEngineStarterFeignConfiguration.java | 7 +- .../consumer/AbstractWorkflowListener.java | 32 ++++- .../consumer/InnerActivityEventListener.java | 47 ++++--- .../consumer/InnerInstanceEventListener.java | 59 ++++----- .../InnerNotificationEventListener.java | 68 +++++----- .../consumer/InnerTaskEventListener.java | 48 ++++--- .../WorkflowEngineBroadcastEventListener.java | 21 +++- .../producer/RpcInvokeEventProducer.java | 109 ++++++++++++++-- .../resources/META-INF/application.yaml.demo | 0 16 files changed, 473 insertions(+), 237 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yaml.demo diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 86593ef77..831f58b85 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -151,4 +151,8 @@ public interface BpmnConstants { * 批量操作配置默认值 */ Boolean SUPPORT_BATCH_OPERATION_DEFAULT_VALUE = false; + /** + * 用于 MQ 的 Header, 记录当前事件的归属应用 + */ + String MQ_ATTRIBUTION_APPS = "MQ_ATTRIBUTION_APPLICATION"; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java index 117ab4875..a2333fd05 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java @@ -17,6 +17,8 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ATTRIBUTION_APPS; + /** * 默认的 RocketMQ 事件生产者的装饰器 * @@ -28,6 +30,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { private BiConsumer> sendBeforeCallback; private BiConsumer> rollbackHandler; + private final String applicationName; public CustomRocketMQEventProducer(RocketMQTemplate rocketMQTemplate, String defaultModule, String appName, Context defaultContext, @@ -35,6 +38,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { BiConsumer> sendAfterCallback, BiConsumer> rollbackHandler) { super(rocketMQTemplate, defaultModule, appName, defaultContext, sendAfterCallback); + this.applicationName = appName; this.sendBeforeCallback = sendBeforeCallback; this.rollbackHandler = rollbackHandler; } @@ -64,6 +68,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); + newHeaders.put(MQ_ATTRIBUTION_APPS, applicationName); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { @@ -89,7 +94,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { } else { // 并发会导致事件时序出现问题. 所以串行执行 log.info("runnable not transaction event={}", copiedEvent.toJsonString()); - getAfterCommitExecutor().executeAndRollback(() -> runnable.run(), () -> rollbackRunnable.run()); + getAfterCommitExecutor().executeAndRollback(runnable, rollbackRunnable); } List runnables = getAfterCommitExecutor().getRunnables(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java new file mode 100644 index 000000000..7fd0a1dd0 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java @@ -0,0 +1,117 @@ +package cn.axzo.workflow.starter; + +import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; + +import java.util.HashSet; +import java.util.Set; + +import static cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum.FAIL_OVER; + +/** + * 监听流程引擎广播的事件时一些行为控制 + *

比如:
+ * 1. 在遇到异常时的处理策略
+ * 2. 过滤事件
+ * 
+ * + * @author wangli + * @since 2024/6/4 14:14 + */ +public class BroadcastListenerConfigurationProperties { + /** + * 是否开启根据应用名过滤 MQ 事件 + */ + private Boolean enableFilterApplicationName = false; + /** + * 是否开启根据业务 ID 集合过滤 MQ 事件 + */ + private Boolean enableFilterDefinitionKey = true; + + /** + * 过滤出 MQ 事件中包含这些业务 ID 的事件 + *

+ * 只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效 + */ + private Set filterProcessDefinitionKeys = new HashSet<>(); + + /** + * 失败处理策略: + *

+     * 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略)
+     * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行
+     * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持
+     * 
+ */ + private FailHandleTypeEnum failHandleType = FAIL_OVER; + + /** + * 自动重试次数 + */ + private int numOfRetries = 3; + + /** + * 初始等待时间,单位:毫秒 + */ + private int waitTimeInMs = 50; + + /** + * 重试累乘因子 + */ + private int waitIncreaseFactor = 3; + + public Boolean getEnableFilterApplicationName() { + return enableFilterApplicationName; + } + + public void setEnableFilterApplicationName(Boolean enableFilterApplicationName) { + this.enableFilterApplicationName = enableFilterApplicationName; + } + + public Boolean getEnableFilterDefinitionKey() { + return enableFilterDefinitionKey; + } + + public void setEnableFilterDefinitionKey(Boolean enableFilterDefinitionKey) { + this.enableFilterDefinitionKey = enableFilterDefinitionKey; + } + + public Set getFilterProcessDefinitionKeys() { + return filterProcessDefinitionKeys; + } + + public void setFilterProcessDefinitionKeys(Set filterProcessDefinitionKeys) { + this.filterProcessDefinitionKeys = filterProcessDefinitionKeys; + } + + public FailHandleTypeEnum getFailHandleType() { + return failHandleType; + } + + public void setFailHandleType(FailHandleTypeEnum failHandleType) { + this.failHandleType = failHandleType; + } + + public int getNumOfRetries() { + return numOfRetries; + } + + public void setNumOfRetries(int numOfRetries) { + this.numOfRetries = numOfRetries; + } + + public int getWaitTimeInMs() { + return waitTimeInMs; + } + + public void setWaitTimeInMs(int waitTimeInMs) { + this.waitTimeInMs = waitTimeInMs; + } + + public int getWaitIncreaseFactor() { + return waitIncreaseFactor; + } + + public void setWaitIncreaseFactor(int waitIncreaseFactor) { + this.waitIncreaseFactor = waitIncreaseFactor; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 920bbae0d..62cbeb158 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -82,7 +82,8 @@ public class WorkflowEngineStarterAutoConfiguration { } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { - FailHandleTypeEnum failHandleType = starterProperties.getFailHandleType(); + BroadcastListenerConfigurationProperties listenerRetry = starterProperties.getListenerRetry(); + FailHandleTypeEnum failHandleType = listenerRetry.getFailHandleType(); log.info("workflow engine starter fail handle type : {}", failHandleType); switch (failHandleType) { case FAIL_BACK: @@ -91,11 +92,10 @@ public class WorkflowEngineStarterAutoConfiguration { return new FailFastInterceptor(); case FAIL_OVER: default: - return new FailOverInterceptor(starterProperties.getNumOfRetries(), - starterProperties.getWaitTimeInMs(), - starterProperties.getWaitIncreaseFactor()); + return new FailOverInterceptor(listenerRetry.getNumOfRetries(), + listenerRetry.getWaitTimeInMs(), + listenerRetry.getWaitIncreaseFactor()); } } - } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 5ed2be18b..a6fd855f6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -3,14 +3,15 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.starter.api.WorkflowCoreService; -import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum.FAIL_OVER; /** * Workflow Engine Starter Properties + *

+ * 全量参数参考:META-INF/application.yaml.demo * * @author wangli * @since 2024/5/21 15:24 @@ -46,35 +47,10 @@ public class WorkflowEngineStarterProperties { private RpcInvokeModeEnum invokeMode = ASYNC; /** - * 失败处理策略: - *

-     * 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略)
-     * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行
-     * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持
-     * 
+ * 监听流程引擎广播的处理器,异常后的重试相关策略及配置 */ - private FailHandleTypeEnum failHandleType = FAIL_OVER; - - /** - * 自动重试次数 - */ - private int numOfRetries = 3; - - /** - * 初始等待时间,单位:毫秒 - */ - private int waitTimeInMs = 50; - - /** - * 重试累乘因子 - */ - private int waitIncreaseFactor = 3; - - /** - * 该属性还不确定能否实现 - */ - @Deprecated - private Boolean autoAck = false; + @NestedConfigurationProperty + private BroadcastListenerConfigurationProperties listenerRetry = new BroadcastListenerConfigurationProperties(); public Boolean getManageable() { return manageable; @@ -100,43 +76,11 @@ public class WorkflowEngineStarterProperties { this.invokeMode = invokeMode; } - public Boolean getAutoAck() { - return autoAck; + public BroadcastListenerConfigurationProperties getListenerRetry() { + return listenerRetry; } - public void setAutoAck(Boolean autoAck) { - this.autoAck = autoAck; - } - - public FailHandleTypeEnum getFailHandleType() { - return failHandleType; - } - - public void setFailHandleType(FailHandleTypeEnum failHandleType) { - this.failHandleType = failHandleType; - } - - public int getNumOfRetries() { - return numOfRetries; - } - - public void setNumOfRetries(int numOfRetries) { - this.numOfRetries = numOfRetries; - } - - public int getWaitTimeInMs() { - return waitTimeInMs; - } - - public void setWaitTimeInMs(int waitTimeInMs) { - this.waitTimeInMs = waitTimeInMs; - } - - public int getWaitIncreaseFactor() { - return waitIncreaseFactor; - } - - public void setWaitIncreaseFactor(int waitIncreaseFactor) { - this.waitIncreaseFactor = waitIncreaseFactor; + public void setListenerRetry(BroadcastListenerConfigurationProperties listenerRetry) { + this.listenerRetry = listenerRetry; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index a0bfdc8a4..8b95166a1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter; +import cn.axzo.framework.domain.data.IdHelper; import cn.axzo.framework.rocketmq.BaseListener; import cn.axzo.framework.rocketmq.DefaultEventConsumer; import cn.axzo.framework.rocketmq.Event; @@ -20,7 +21,6 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -29,13 +29,19 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.BiConsumer; import java.util.function.Consumer; +import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ATTRIBUTION_APPS; + /** * 配置 RocketMQ 事件监听器 * @@ -48,7 +54,6 @@ public class WorkflowEngineStarterRocketMQConfiguration { private static final String DEFAULT_MODULE = "workflowEngine"; private static final String DEFAULT_EVENT = "topic_workflow_engine_"; - @Value("${spring.application.name}") private String applicationName; @Value("${spring.profiles.active:dev}") @@ -87,19 +92,35 @@ public class WorkflowEngineStarterRocketMQConfiguration { nameServer = "${rocketmq.name-server}" ) public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); @Resource(name = "eventConsumer") private EventConsumer eventConsumer; + @Resource + private WorkflowEngineStarterProperties workflowEngineStarterProperties; + @Value("${spring.application.name}") + private String applicationName; @Override public void onMessage(MessageExt message) { - super.onEvent(message, eventConsumer); + if (workflowEngineStarterProperties.getListenerRetry().getEnableFilterApplicationName()) { + Map properties = message.getProperties(); + String mqAttributionApp = properties.getOrDefault(MQ_ATTRIBUTION_APPS, null); + if (StringUtils.hasText(mqAttributionApp) && Objects.equals(mqAttributionApp, applicationName)) { + super.onEvent(message, eventConsumer); + } else { + log.info("broadcast message not attribution this application, will be ignored. messageId: {}", message.getMsgId()); + } + } else { + super.onEvent(message, eventConsumer); + } } } @Bean public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, - ObjectProvider> listenerProvider) { - return new WorkflowEngineBroadcastEventListener(eventConsumer, listenerProvider); + WorkflowEngineStarterProperties workflowEngineStarterProperties, + List listenerProvider) { + return new WorkflowEngineBroadcastEventListener(eventConsumer, workflowEngineStarterProperties, listenerProvider); } @@ -112,8 +133,8 @@ public class WorkflowEngineStarterRocketMQConfiguration { * @return */ @Bean - public EventProducer workflowEngineClientEventProducer(RocketMQTemplate rocketMQTemplate) { - return new RocketMQEventProducer(rocketMQTemplate, + public EventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { + return new RpcInvokeEventProducer(rocketMQTemplate, DEFAULT_MODULE, applicationName + "Starter", EventProducer.Context.builder() @@ -129,16 +150,51 @@ public class WorkflowEngineStarterRocketMQConfiguration { context.getThrowable()); }) .build(), - (event, context) -> { - // 调用 Rocket 发送 API 后的回调,不代表真实发送 - } + getSendBeforeCallback(), + getSendAfterCallback(), + getTransactionRollbackHandler() ); } - @Bean - public RpcInvokeEventProducer rpcInvokeEventProducer(@Qualifier("workflowEngineClientEventProducer") EventProducer workflowEngineClientEventProducer, - Environment environment) { - return new RpcInvokeEventProducer(workflowEngineClientEventProducer, environment); + /** + * 真实执行 MQ 发送前的回调, + *

+ * 将整个待发送的事件内容通过 spring 的事件分发器发送出去, 现目前主要是记录 MQ 的发送记录 + * + * @return + */ + private BiConsumer> getSendBeforeCallback() { + return (event, context) -> { + event.setEventId(IdHelper.get32UUID()); + log.info("mq_send_Before: {}, uniqueId: {}", event.getShardingKey(), event.getEventId()); + }; + } + + /** + * 真实执行 MQ 发送后的回调 + *

+ * 将发送前的 MQ 发送记录更新 MQ 组件自己的 MessageId 字段。 + * + * @return + */ + private BiConsumer> getSendAfterCallback() { + return (event, context) -> { + String messageId = context.getHeaders().get(MQ_MESSAGE_ID); + log.info("mq_send_after: {}, uniqueId: {}, messageId: {}", event.getShardingKey(), event.getEventId(), messageId); + }; + } + + /** + * 如果 MQ 注册的事务回滚后的回调 + *

+ * 将 MQ 发送记录更新为删除状态,意为这类数据可以不关注,可以物理删除,但该功能还是用逻辑删除。 + * + * @return + */ + private BiConsumer> getTransactionRollbackHandler() { + return (event, context) -> { + log.info("mq_transaction_rollback: {}, uniqueId: {}", event.getShardingKey(), event.getEventId()); + }; } @Bean @@ -175,12 +231,22 @@ public class WorkflowEngineStarterRocketMQConfiguration { nameServer = "${rocketmq.name-server}" ) public static class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineClientRetryConsumer.class); @Resource(name = "workflowEngineStarterEventConsumer") private EventConsumer workflowEngineStarterEventConsumer; + @Value("${spring.application.name}") + private String applicationName; @Override public void onMessage(MessageExt message) { - super.onEvent(message, workflowEngineStarterEventConsumer); + Map properties = message.getProperties(); + String mqAttributionApp = properties.getOrDefault(MQ_ATTRIBUTION_APPS, null); + if (StringUtils.hasText(mqAttributionApp) && Objects.equals(mqAttributionApp, applicationName)) { + super.onEvent(message, workflowEngineStarterEventConsumer); + } else { + log.info("rpc retry message not attribution this application, will be ignored. messageId: {}", message.getMsgId()); + } + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 14dc72c2b..d0f4932a2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.common.util.ThreadUtil; @@ -63,14 +64,14 @@ public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); private final WorkflowEngineStarterProperties starterProperties; - private final RpcInvokeEventProducer rpcInvokeEventProducer; + private final RpcInvokeEventProducer eventProducer; private final Client feignClient; public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, - RpcInvokeEventProducer rpcInvokeEventProducer, + EventProducer eventProducer, Client feignClient) { this.starterProperties = starterProperties; - this.rpcInvokeEventProducer = rpcInvokeEventProducer; + this.eventProducer = (RpcInvokeEventProducer) eventProducer; this.feignClient = feignClient; } @@ -114,7 +115,7 @@ public class ComplexInvokeClient implements Client { event.setParameters(args); buildArgs(request, metadata, args); - rpcInvokeEventProducer.send(WORKFLOW_ENGINE_STARTER, event); + eventProducer.send(WORKFLOW_ENGINE_STARTER, event); } @SneakyThrows diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index dbbbd4d54..0a122812b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -1,9 +1,9 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import feign.Client; import feign.RequestInterceptor; import feign.Target; @@ -11,6 +11,7 @@ import feign.codec.Decoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; @@ -37,9 +38,9 @@ public class WorkflowEngineStarterFeignConfiguration { @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, - RpcInvokeEventProducer rpcInvokeEventProducer, + @Qualifier("workflowEngineStarterEventProducer") EventProducer eventProducer, Client feignClient) { - return new ComplexInvokeClient(starterProperties, rpcInvokeEventProducer, feignClient); + return new ComplexInvokeClient(starterProperties, eventProducer, feignClient); } @Bean diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index 0e406c967..7f8030139 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -1,9 +1,13 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.core.Ordered; +import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.Comparator; @@ -12,23 +16,41 @@ import java.util.stream.Collectors; public abstract class AbstractWorkflowListener implements WorkflowListener { - private final ObjectProvider> listenerProvider; - + private static final Logger log = LoggerFactory.getLogger(AbstractWorkflowListener.class); + protected final List businessListeners; private final ListenerExecutor listenerExecutor; + public AbstractWorkflowListener(ListenerExecutor listenerExecutor, ObjectProvider> provider) { this.listenerExecutor = listenerExecutor; - this.listenerProvider = provider; + this.businessListeners = getOrderedBusinessListeners(provider); } + protected final boolean emptyListener() { + if (CollectionUtils.isEmpty(businessListeners)) { + log.info("not {}'s Bean found, will be skip it. please check @Component annotation...", this.getClass().getSimpleName()); + return true; + } + return false; + } - protected List getCustomListeners() { - return listenerProvider.getIfAvailable(Collections::emptyList) + protected List getOrderedBusinessListeners(ObjectProvider> provider) { + return provider.getIfAvailable(Collections::emptyList) .stream() .sorted(Comparator.comparingInt(Ordered::getOrder)) .collect(Collectors.toList()); } + @Override + public void handleEvent(Event event, EventConsumer.Context context) { + if (emptyListener()) { + return; + } + onEvent(event, context); + } + + protected abstract void onEvent(Event event, EventConsumer.Context context); + protected ListenerExecutor getListenerExecutor() { return listenerExecutor; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 57de1fa40..c95c2e256 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -6,11 +6,9 @@ import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.util.CollectionUtils; import java.util.Arrays; import java.util.List; @@ -34,31 +32,28 @@ public class InnerActivityEventListener extends AbstractWorkflowListener activityListeners = getCustomListeners(); - if (!CollectionUtils.isEmpty(activityListeners)) { - ProcessActivityDTO activityDTO = JSON.parseObject(event.getData().toString(), ProcessActivityDTO.class); - ProcessActivityEventEnum type = activityDTO.getType(); - for (ProcessActivityEventHandler activityListener : activityListeners) { - Consumer consumer = null; - switch (type) { - case PROCESS_ACTIVITY_START: - consumer = activityListener::onStart; - break; - case PROCESS_ACTIVITY_WAIT_ASSIGNEE: - consumer = activityListener::onWaitAssignee; - break; - case PROCESS_ACTIVITY_TAKE: - consumer = activityListener::onTake; - break; - case PROCESS_ACTIVITY_END: - consumer = activityListener::onEnd; - break; - default: - log.warn("unknown process activity event type: {}", type); - } - getListenerExecutor().execute(consumer, activityDTO); + public void onEvent(Event event, EventConsumer.Context context) { + ProcessActivityDTO activityDTO = event.normalizedData(ProcessActivityDTO.class); + ProcessActivityEventEnum type = activityDTO.getType(); + for (ProcessActivityEventHandler activityListener : businessListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_ACTIVITY_START: + consumer = activityListener::onStart; + break; + case PROCESS_ACTIVITY_WAIT_ASSIGNEE: + consumer = activityListener::onWaitAssignee; + break; + case PROCESS_ACTIVITY_TAKE: + consumer = activityListener::onTake; + break; + case PROCESS_ACTIVITY_END: + consumer = activityListener::onEnd; + break; + default: + log.warn("unknown process activity event type: {}", type); } + getListenerExecutor().execute(consumer, activityDTO); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index e93b9debc..e763e45e5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -6,11 +6,9 @@ import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.util.CollectionUtils; import java.util.Arrays; import java.util.List; @@ -34,37 +32,34 @@ public class InnerInstanceEventListener extends AbstractWorkflowListener instanceListeners = getCustomListeners(); - if (!CollectionUtils.isEmpty(instanceListeners)) { - ProcessInstanceDTO instanceDTO = JSON.parseObject(event.getData().toString(), ProcessInstanceDTO.class); - ProcessInstanceEventEnum type = instanceDTO.getType(); - for (ProcessInstanceEventHandler instanceListener : instanceListeners) { - Consumer consumer = null; - switch (type) { - case PROCESS_INSTANCE_CREATED: - consumer = instanceListener::onCreated; - break; - case PROCESS_INSTANCE_STARTED: - consumer = instanceListener::onStarted; - break; - case PROCESS_INSTANCE_CANCELLED: - consumer = instanceListener::onCancelled; - break; - case PROCESS_INSTANCE_ABORTED: - consumer = instanceListener::onAborted; - break; - case PROCESS_INSTANCE_COMPLETED: - consumer = instanceListener::onCompleted; - break; - case PROCESS_INSTANCE_REJECTED: - consumer = instanceListener::onRejected; - break; - default: - log.warn("unknown process activity event type: {}", type); - } - getListenerExecutor().execute(consumer, instanceDTO); + public void onEvent(Event event, EventConsumer.Context context) { + ProcessInstanceDTO instanceDTO = event.normalizedData(ProcessInstanceDTO.class); + ProcessInstanceEventEnum type = instanceDTO.getType(); + for (ProcessInstanceEventHandler instanceListener : businessListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_INSTANCE_CREATED: + consumer = instanceListener::onCreated; + break; + case PROCESS_INSTANCE_STARTED: + consumer = instanceListener::onStarted; + break; + case PROCESS_INSTANCE_CANCELLED: + consumer = instanceListener::onCancelled; + break; + case PROCESS_INSTANCE_ABORTED: + consumer = instanceListener::onAborted; + break; + case PROCESS_INSTANCE_COMPLETED: + consumer = instanceListener::onCompleted; + break; + case PROCESS_INSTANCE_REJECTED: + consumer = instanceListener::onRejected; + break; + default: + log.warn("unknown process activity event type: {}", type); } + getListenerExecutor().execute(consumer, instanceDTO); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java index e6ef6d4fb..8ed0b875a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java @@ -2,16 +2,13 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.util.CollectionUtils; import java.util.Arrays; import java.util.List; @@ -27,7 +24,7 @@ public class InnerNotificationEventListener extends AbstractWorkflowListener> SUPPORTED_EVENT_CODES_SUPPLIER = () -> - Arrays.stream(ProcessInstanceEventEnum.values()).map(ProcessInstanceEventEnum::getEventCode) + Arrays.stream(ProcessMessagePushEventEnum.values()).map(ProcessMessagePushEventEnum::getEventCode) .collect(Collectors.toList()); public InnerNotificationEventListener(ListenerExecutor executor, ObjectProvider> provider) { @@ -35,40 +32,37 @@ public class InnerNotificationEventListener extends AbstractWorkflowListener instanceListeners = getCustomListeners(); - if (!CollectionUtils.isEmpty(instanceListeners)) { - MessagePushDTO instanceDTO = JSON.parseObject(event.getData().toString(), MessagePushDTO.class); - ProcessMessagePushEventEnum type = instanceDTO.getType(); - for (MessageNotificationEventHandler noticeListener : instanceListeners) { - Consumer consumer = null; - switch (type) { - case PROCESS_PUSH_NOTICE: - consumer = noticeListener::pushNotice; - break; - case PROCESS_PUSH_PENDING: - consumer = noticeListener::pushPending; - break; - case PROCESS_PUSH_PENDING_COMPLETE: - consumer = noticeListener::completePending; - break; - case PROCESS_PUSH_PENDING_ROLLBACK: - consumer = noticeListener::rollbackPending; - break; - case PROCESS_CARBON_COPY: - consumer = noticeListener::carbonCopy; - break; - case PROCESS_CARBON_COPY_COMPLETE: - consumer = noticeListener::carbonCopyComplete; - break; - case PROCESS_PUSH_SMS: - consumer = noticeListener::pushSms; - break; - default: - log.warn("unknown message event type: {}", type); - } - getListenerExecutor().execute(consumer, instanceDTO); + public void onEvent(Event event, EventConsumer.Context context) { + MessagePushDTO instanceDTO = event.normalizedData(MessagePushDTO.class); + ProcessMessagePushEventEnum type = instanceDTO.getType(); + for (MessageNotificationEventHandler noticeListener : businessListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_PUSH_NOTICE: + consumer = noticeListener::pushNotice; + break; + case PROCESS_PUSH_PENDING: + consumer = noticeListener::pushPending; + break; + case PROCESS_PUSH_PENDING_COMPLETE: + consumer = noticeListener::completePending; + break; + case PROCESS_PUSH_PENDING_ROLLBACK: + consumer = noticeListener::rollbackPending; + break; + case PROCESS_CARBON_COPY: + consumer = noticeListener::carbonCopy; + break; + case PROCESS_CARBON_COPY_COMPLETE: + consumer = noticeListener::carbonCopyComplete; + break; + case PROCESS_PUSH_SMS: + consumer = noticeListener::pushSms; + break; + default: + log.warn("unknown message event type: {}", type); } + getListenerExecutor().execute(consumer, instanceDTO); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 3dda9fa20..6d369ef7a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -6,11 +6,9 @@ import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.util.CollectionUtils; import java.util.Arrays; import java.util.List; @@ -34,32 +32,30 @@ public class InnerTaskEventListener extends AbstractWorkflowListener taskListeners = getCustomListeners(); - if (!CollectionUtils.isEmpty(taskListeners)) { - ProcessTaskDTO taskDTO = JSON.parseObject(event.getData().toString(), ProcessTaskDTO.class); - ProcessTaskEventEnum type = taskDTO.getType(); - for (ProcessTaskEventHandler taskListener : taskListeners) { - Consumer consumer = null; - switch (type) { - case PROCESS_TASK_CREATED: - consumer = taskListener::onCreated; - break; - case PROCESS_TASK_COMPLETED: - consumer = taskListener::onCompleted; - break; - case PROCESS_TASK_ASSIGNED: - consumer = taskListener::onAssigned; - break; - case PROCESS_TASK_DELETED: - consumer = taskListener::onDeleted; - break; - default: - log.warn("unknown task event type: {}", type); - } - getListenerExecutor().execute(consumer, taskDTO); + public void onEvent(Event event, EventConsumer.Context context) { + ProcessTaskDTO taskDTO = event.normalizedData(ProcessTaskDTO.class); + ProcessTaskEventEnum type = taskDTO.getType(); + for (ProcessTaskEventHandler taskListener : businessListeners) { + Consumer consumer = null; + switch (type) { + case PROCESS_TASK_CREATED: + consumer = taskListener::onCreated; + break; + case PROCESS_TASK_COMPLETED: + consumer = taskListener::onCompleted; + break; + case PROCESS_TASK_ASSIGNED: + consumer = taskListener::onAssigned; + break; + case PROCESS_TASK_DELETED: + consumer = taskListener::onDeleted; + break; + default: + log.warn("unknown task event type: {}", type); } + getListenerExecutor().execute(consumer, taskDTO); } + } @Override diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index fcd300b6a..fb75a764c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -3,13 +3,13 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.CollectionUtils; -import java.util.Collections; import java.util.List; import java.util.Objects; @@ -22,11 +22,13 @@ import java.util.Objects; public class WorkflowEngineBroadcastEventListener implements EventHandler, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastEventListener.class); private final EventConsumer eventConsumer; - private final ObjectProvider> workflowListenersProvider; + private final WorkflowEngineStarterProperties starterProperties; + private final List workflowListeners; - public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, ObjectProvider> workflowListenersProvider) { + public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List workflowListeners) { this.eventConsumer = eventConsumer; - this.workflowListenersProvider = workflowListenersProvider; + this.starterProperties = workflowEngineStarterProperties; + this.workflowListeners = workflowListeners; } @Override @@ -36,7 +38,13 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi return; } - List workflowListeners = workflowListenersProvider.getIfAvailable(Collections::emptyList); + try { + JSON.parse(JSON.toJSONString(event.getData())); + } catch (Exception e) { + log.warn("event data json format error, will be ignored, messageId: {}", context.getMsgId()); + return; + } + if (CollectionUtils.isEmpty(workflowListeners)) { log.warn("no business listeners implementation found, please check @Component annotation"); return; @@ -56,4 +64,5 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi eventConsumer.registerHandlers(InnerNotificationEventListener.SUPPORTED_EVENT_CODES_SUPPLIER.get(), this); eventConsumer.registerHandlers(InnerTaskEventListener.SUPPORTED_EVENT_CODES_SUPPLIER.get(), this); } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index 3c341ee67..cf43b594a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -1,10 +1,26 @@ package cn.axzo.workflow.starter.mq.retry.producer; import cn.axzo.framework.rocketmq.Event; -import cn.axzo.framework.rocketmq.EventProducer; +import cn.axzo.framework.rocketmq.RocketMQEventProducer; +import cn.axzo.framework.rocketmq.utils.TraceUtils; import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; -import org.springframework.core.env.Environment; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import lombok.NonNull; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; + +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ATTRIBUTION_APPS; /** * RPC 的调用动作的 MQ 事件生产者 @@ -12,14 +28,85 @@ import org.springframework.core.env.Environment; * @author wangli * @since 2024/5/22 10:02 */ -public class RpcInvokeEventProducer { +public class RpcInvokeEventProducer extends RocketMQEventProducer { + private final Logger log = LoggerFactory.getLogger(RpcInvokeEventProducer.class); - private final EventProducer workflowEngineClientEventProducer; - private final String currentApplicationName; + private BiConsumer> sendBeforeCallback; + private BiConsumer> rollbackHandler; + private final String applicationName; - public RpcInvokeEventProducer(EventProducer workflowEngineClientEventProducer, Environment environment) { - this.workflowEngineClientEventProducer = workflowEngineClientEventProducer; - this.currentApplicationName = environment.getProperty("spring.application.name"); + public RpcInvokeEventProducer(RocketMQTemplate rocketMQTemplate, String defaultModule, + String appName, Context defaultContext, + BiConsumer> sendBeforeCallback, + BiConsumer> sendAfterCallback, + BiConsumer> rollbackHandler) { + super(rocketMQTemplate, defaultModule, appName, defaultContext, sendAfterCallback); + this.applicationName = appName; + this.sendBeforeCallback = sendBeforeCallback; + this.rollbackHandler = rollbackHandler; + } + + @Override + public void send(@NonNull Event event, @NonNull Context context) { + log.info("发送事件内容:{}", event.toPrettyJsonString()); + if (sendBeforeCallback != null) { + sendBeforeCallback.accept(event, context); + } + // XXX:不要在send的时候修改event的值,有副作用。 + // 例如:当将同一个event发送到不同的topic的时候,buildSchemaHash会用不同的topic赋值两次,导致一些异常case + Event copiedEvent = Event.builder().build(); + BeanUtils.copyProperties(event, copiedEvent); + if (Strings.isNullOrEmpty(copiedEvent.getTargetId())) { + log.warn("targetId of event is black, best practice of targetId is present, event = {}", event.toJsonString()); + } + + if (copiedEvent.getData() == null) { + log.warn("data of event is empty, best practice of data must present, event = {}", event.toJsonString()); + } + Preconditions.checkArgument(!Strings.isNullOrEmpty(copiedEvent.getEventModule()), "eventModule不能为空"); + Preconditions.checkArgument(!Strings.isNullOrEmpty(copiedEvent.getEventName()), "eventName不能为空"); + + // 复制一份 context,并加入链路跟踪信息 traceId + HashMap newHeaders = Maps.newHashMap(Optional.ofNullable(context.getHeaders()).orElse(ImmutableMap.of())); + newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId()); + newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); + newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); + newHeaders.put(MQ_ATTRIBUTION_APPS, applicationName); + final Context copiedContext = context.toBuilder().headers(newHeaders).build(); + + Runnable runnable = () -> { + try { + getSender().accept(copiedEvent, copiedContext); + } catch (Exception e) { + log.error("====MQ PRODUCER ====, context={}, message = {}", copiedContext, copiedEvent.toPrettyJsonString(), e); + throw e; + } + }; + + Runnable rollbackRunnable = () -> { + try { + getRollbackHandler().accept(copiedEvent, copiedContext); + } catch (Exception e) { + // ignore + } + }; + if (copiedContext.isTransactional()) { + // https://www.jianshu.com/p/59891ede5f90 + log.info("runnable is transaction event={}", copiedEvent.toJsonString()); + runnable.run(); + } else { + // 并发会导致事件时序出现问题. 所以串行执行 + log.info("runnable not transaction event={}", copiedEvent.toJsonString()); + getAfterCommitExecutor().executeAndRollback(runnable, rollbackRunnable); + } + + List runnables = getAfterCommitExecutor().getRunnables(); + log.info("runnables.size(): {}", runnables.size()); + } + + @Override + public BiConsumer> getRollbackHandler() { + return rollbackHandler; } /** @@ -29,9 +116,9 @@ public class RpcInvokeEventProducer { * @param data {@link WorkflowEngineStarterRpcInvokeDTO} */ public void send(WorkflowEngineEventEnum eventEnum, WorkflowEngineStarterRpcInvokeDTO data) { - workflowEngineClientEventProducer.send(Event.builder() - .shardingKey(currentApplicationName) - .eventCode(eventEnum.getEventCode(currentApplicationName)) + send(Event.builder() + .shardingKey(applicationName) + .eventCode(eventEnum.getEventCode(applicationName)) .targetId(data.getMethodName()) .targetType(eventEnum.getTag()) .data(data) diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yaml.demo b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yaml.demo new file mode 100644 index 000000000..e69de29bb From aabded6ea89890bbece755910d48bee1f2611d41 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 16:53:03 +0800 Subject: [PATCH 064/210] =?UTF-8?q?update(REQ-2324)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20MQ=20=E5=8F=91=E9=80=81=E6=96=B9=E7=9A=84=E5=BD=92?= =?UTF-8?q?=E5=B1=9E=E5=B1=9E=E6=80=A7=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/constant/BpmnConstants.java | 2 +- .../core/mq/CustomRocketMQEventProducer.java | 4 ++-- .../WorkflowEngineStarterAutoConfiguration.java | 2 +- .../starter/WorkflowEngineStarterProperties.java | 10 +++++----- ...rkflowEngineStarterRocketMQConfiguration.java | 16 ++++++++-------- .../retry/producer/RpcInvokeEventProducer.java | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 831f58b85..69865ff76 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -154,5 +154,5 @@ public interface BpmnConstants { /** * 用于 MQ 的 Header, 记录当前事件的归属应用 */ - String MQ_ATTRIBUTION_APPS = "MQ_ATTRIBUTION_APPLICATION"; + String MQ_OWNERSHIP_APP = "MQ_OWNERSHIP_APPLICATION"; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java index a2333fd05..2cedf5fe5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java @@ -17,7 +17,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ATTRIBUTION_APPS; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; /** * 默认的 RocketMQ 事件生产者的装饰器 @@ -68,7 +68,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); - newHeaders.put(MQ_ATTRIBUTION_APPS, applicationName); + newHeaders.put(MQ_OWNERSHIP_APP, applicationName); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 62cbeb158..2f2a7b088 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -82,7 +82,7 @@ public class WorkflowEngineStarterAutoConfiguration { } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { - BroadcastListenerConfigurationProperties listenerRetry = starterProperties.getListenerRetry(); + BroadcastListenerConfigurationProperties listenerRetry = starterProperties.getBroadcast(); FailHandleTypeEnum failHandleType = listenerRetry.getFailHandleType(); log.info("workflow engine starter fail handle type : {}", failHandleType); switch (failHandleType) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index a6fd855f6..a9b045a16 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -50,7 +50,7 @@ public class WorkflowEngineStarterProperties { * 监听流程引擎广播的处理器,异常后的重试相关策略及配置 */ @NestedConfigurationProperty - private BroadcastListenerConfigurationProperties listenerRetry = new BroadcastListenerConfigurationProperties(); + private BroadcastListenerConfigurationProperties broadcast = new BroadcastListenerConfigurationProperties(); public Boolean getManageable() { return manageable; @@ -76,11 +76,11 @@ public class WorkflowEngineStarterProperties { this.invokeMode = invokeMode; } - public BroadcastListenerConfigurationProperties getListenerRetry() { - return listenerRetry; + public BroadcastListenerConfigurationProperties getBroadcast() { + return broadcast; } - public void setListenerRetry(BroadcastListenerConfigurationProperties listenerRetry) { - this.listenerRetry = listenerRetry; + public void setBroadcast(BroadcastListenerConfigurationProperties broadcast) { + this.broadcast = broadcast; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index 8b95166a1..bba0a7f89 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -40,7 +40,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ATTRIBUTION_APPS; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; /** * 配置 RocketMQ 事件监听器 @@ -102,13 +102,13 @@ public class WorkflowEngineStarterRocketMQConfiguration { @Override public void onMessage(MessageExt message) { - if (workflowEngineStarterProperties.getListenerRetry().getEnableFilterApplicationName()) { + if (workflowEngineStarterProperties.getBroadcast().getEnableFilterApplicationName()) { Map properties = message.getProperties(); - String mqAttributionApp = properties.getOrDefault(MQ_ATTRIBUTION_APPS, null); - if (StringUtils.hasText(mqAttributionApp) && Objects.equals(mqAttributionApp, applicationName)) { + String mqOwnerShip = properties.getOrDefault(MQ_OWNERSHIP_APP, null); + if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { super.onEvent(message, eventConsumer); } else { - log.info("broadcast message not attribution this application, will be ignored. messageId: {}", message.getMsgId()); + log.info("broadcast message not attribution this application, will be ignored. messageId: {}, mq-ownership: {}", message.getMsgId(), mqOwnerShip); } } else { super.onEvent(message, eventConsumer); @@ -240,11 +240,11 @@ public class WorkflowEngineStarterRocketMQConfiguration { @Override public void onMessage(MessageExt message) { Map properties = message.getProperties(); - String mqAttributionApp = properties.getOrDefault(MQ_ATTRIBUTION_APPS, null); - if (StringUtils.hasText(mqAttributionApp) && Objects.equals(mqAttributionApp, applicationName)) { + String mqOwnerShip = properties.getOrDefault(MQ_OWNERSHIP_APP, null); + if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { super.onEvent(message, workflowEngineStarterEventConsumer); } else { - log.info("rpc retry message not attribution this application, will be ignored. messageId: {}", message.getMsgId()); + log.info("rpc retry message not attribution this application, will be ignored. messageId: {}, mq-ownership: {}", message.getMsgId(), mqOwnerShip); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index cf43b594a..fc5954a89 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ATTRIBUTION_APPS; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; /** * RPC 的调用动作的 MQ 事件生产者 @@ -71,7 +71,7 @@ public class RpcInvokeEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); - newHeaders.put(MQ_ATTRIBUTION_APPS, applicationName); + newHeaders.put(MQ_OWNERSHIP_APP, applicationName); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { From 139e5ee44886cc68d38fd377305ed021bb25a9e7 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 16:55:11 +0800 Subject: [PATCH 065/210] =?UTF-8?q?update(REQ-2324)=20-=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E7=A7=BB=E9=99=A4=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService_Gen.java | 160 +++++++++--------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java index 5782452f1..94392484c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java @@ -33,6 +33,17 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import cn.azxo.framework.common.model.CommonResponse; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; +import java.lang.Boolean; +import java.lang.Integer; +import java.lang.Object; +import java.lang.String; +import java.lang.Void; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -41,255 +52,248 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; -import javax.annotation.Nullable; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; -import java.util.Map; - public interface WorkflowCoreService_Gen { @Operation( - summary = "待审核列表" + summary = "待审核列表" ) @GetMapping("/api/process/task/page/todo") CommonResponse> getTodoTaskPage( - @Validated @RequestBody BpmnTaskPageSearchDTO dto); + @Validated @RequestBody BpmnTaskPageSearchDTO dto); @Operation( - summary = "已完成的审批列表" + summary = "已完成的审批列表" ) @GetMapping("/api/process/task/page/done") CommonResponse> getDoneTaskPage( - @Validated @RequestBody BpmnTaskPageSearchDTO dto); + @Validated @RequestBody BpmnTaskPageSearchDTO dto); @Operation( - summary = "获取指定流程实例的审批过程信息" + summary = "获取指定流程实例的审批过程信息" ) @GetMapping("/api/process/task/list/flat") CommonResponse> getTaskListFlatByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); @Operation( - summary = "获取指定流程实例的审批过程信息" + summary = "获取指定流程实例的审批过程信息" ) @GetMapping("/api/process/task/list/group") CommonResponse> getTaskListGroupByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); @Operation( - summary = "获取实例正在审核的人列表" + summary = "获取实例正在审核的人列表" ) @GetMapping("/api/process/task/active/list") CommonResponse> getActiveTasksByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @NotBlank(message = "租户不能为空") @RequestParam String tenantId); @Operation( - summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件" + summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件" ) @PostMapping("/api/process/task/approve") CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); @Operation( - summary = "批量同意" + summary = "批量同意" ) @PostMapping("/api/process/task/batch/approve") CommonResponse batchApproveTask( - @Validated @RequestBody List dtos); + @Validated @RequestBody List dtos); @Operation( - summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件" + summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件" ) @PostMapping("/api/process/task/reject") CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); @PostMapping("/api/process/task/batch/reject") CommonResponse batchRejectTask( - @Validated @RequestBody List dtos); + @Validated @RequestBody List dtos); @Operation( - summary = "直接修改审批任务的审批人" + summary = "直接修改审批任务的审批人" ) @PostMapping("/api/process/task/transfer") CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); @Operation( - summary = "批量修改审批任务的审批人" + summary = "批量修改审批任务的审批人" ) @PostMapping("/api/process/task/batch/transfer") CommonResponse batchTransferTask( - @Validated @RequestBody List dtos); + @Validated @RequestBody List dtos); @Operation( - summary = "审批流程评论" + summary = "审批流程评论" ) @PostMapping("/api/process/task/comment") CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); @Operation( - summary = "添加附件" + summary = "添加附件" ) @PostMapping("/api/process/task/attachment") CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); @Operation( - summary = "审批流程加签" + summary = "审批流程加签" ) @PostMapping("/api/process/task/countersign") CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); @Operation( - summary = "审批流程催办" + summary = "审批流程催办" ) @PostMapping("/api/process/task/remind") CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); @Operation( - summary = "创建机器人节点, 暂停流程任务" + summary = "创建机器人节点, 暂停流程任务" ) @PostMapping("/api/process/task/robot/create") CommonResponse createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); @Operation( - summary = "完成机器人节点, 继续流程任务" + summary = "完成机器人节点, 继续流程任务" ) @PostMapping("/api/process/task/robot/complete") CommonResponse completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); @Operation( - summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" + summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" ) @GetMapping("/api/process/task/find") CommonResponse findTaskIdByInstanceIdAndPersonId( - @RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, - @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + @RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, + @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); @Operation( - summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" + summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" ) @GetMapping("/api/process/task/batch/find") CommonResponse> findTaskIdByInstanceIdsAndPersonId( - @RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, - @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + @RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, + @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); @Operation( - summary = "查询所有的审批流" + summary = "查询所有的审批流" ) @PostMapping("/api/process/instance/page/all") CommonResponse> getAllProcessInstancePage( - @Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); + @Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); @Operation( - summary = "我发起的审批列表" + summary = "我发起的审批列表" ) @PostMapping("/api/process/instance/page/my") CommonResponse> getMyProcessInstancePage( - @Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); + @Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); @Operation( - summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件" + summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件" ) @PostMapping("/api/process/instance/create") CommonResponse createProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + @Validated @RequestBody BpmnProcessInstanceCreateDTO dto); @Operation( - summary = "创建审批流程并带上表单" + summary = "创建审批流程并带上表单" ) @PostMapping("/api/process/instance/form/create") CommonResponse createProcessInstanceWith( - @Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); + @Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); @Operation( - summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件" + summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件" ) @DeleteMapping("/api/process/instance/cancel") CommonResponse cancelProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCancelDTO dto); + @Validated @RequestBody BpmnProcessInstanceCancelDTO dto); @Operation( - summary = "中止流程实例" + summary = "中止流程实例" ) @DeleteMapping("/api/process/instance/abort") CommonResponse abortProcessInstance( - @Validated @RequestBody BpmnProcessInstanceAbortDTO dto); + @Validated @RequestBody BpmnProcessInstanceAbortDTO dto); @Operation( - summary = "批量中止流程实例" + summary = "批量中止流程实例" ) @DeleteMapping("/api/process/instance/batch/abort") CommonResponse batchAbortProcessInstance( - @Validated @RequestBody List dtos); + @Validated @RequestBody List dtos); @Operation( - summary = "抄送流程实例" + summary = "抄送流程实例" ) @PostMapping("/api/process/instance/carbon-copy") CommonResponse carbonCopyProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); + @Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); @Operation( - summary = "获得流程实例" + summary = "获得流程实例" ) @GetMapping("/api/process/instance/get") CommonResponse getProcessInstanceVO( - @Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + @Validated @RequestBody BpmnProcessInstanceQueryDTO dto); @Operation( - summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" + summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" ) @PutMapping("/api/process/instance/status/update") CommonResponse updateProcessStatus( - @NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, - @NotNull(message = "状态不能为空") @RequestParam Integer status); + @NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, + @NotNull(message = "状态不能为空") @RequestParam Integer status); @Operation( - summary = "获取审批流程实例的运行图" + summary = "获取审批流程实例的运行图" ) @GetMapping("/api/process/instance/graphical") CommonResponse processInstanceGraphical( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); @Operation( - summary = "推断指定流程实例的所有节点执行顺序" + summary = "推断指定流程实例的所有节点执行顺序" ) @GetMapping("/api/process/instance/node/forecasting") CommonResponse> processInstanceNodeForecast( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); @Operation( - summary = "推断指定流程实例的过滤掉部分节点执行顺序" + summary = "推断指定流程实例的过滤掉部分节点执行顺序" ) @GetMapping("/api/process/instance/node/filter/forecasting") CommonResponse> processInstanceFilterNodeForecast( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId, - @RequestParam(required = false, defaultValue = "false") Boolean allNode, - @Nullable @RequestParam(required = false) List nodeDefinitionKeys); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId, + @RequestParam(required = false, defaultValue = "false") Boolean allNode, + @Nullable @RequestParam(required = false) List nodeDefinitionKeys); @Operation( - summary = "获取指定流程实例的流程变量" + summary = "获取指定流程实例的流程变量" ) @GetMapping("/api/process/instance/cooperation-org") CommonResponse> getProcessVariables( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); + @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); @Operation( - summary = "查询实例的租户集合" + summary = "查询实例的租户集合" ) @GetMapping("/api/process/instance/tenant/ids") CommonResponse> getTenantIds(); @Operation( - summary = "校验指定流程实例下,是否存在指定的审批人" + summary = "校验指定流程实例下,是否存在指定的审批人" ) @PostMapping("/api/process/instance/check/approver") CommonResponse checkInstanceApprover( - @Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); + @Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); } From 3e8f131d2320a2c2904f05c4d6cbe6e5b50130a3 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 18:28:57 +0800 Subject: [PATCH 066/210] =?UTF-8?q?update(REQ-2324)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=9B=91=E5=90=AC=E6=B5=81=E7=A8=8B=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E5=B9=BF=E6=92=AD=E4=BA=8B=E4=BB=B6=E4=B8=AD=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E8=BF=87=E6=BB=A4=E4=BA=8B=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/mq/CustomRocketMQEventProducer.java | 4 +- ...orkflowEngineStarterAutoConfiguration.java | 14 ++--- ...lowEngineStarterRocketMQConfiguration.java | 57 ++++++++++++------- .../listener/BroadcastMessageQueueFilter.java | 15 +++++ .../execute/ListenerExecutor.java | 4 +- .../AbstractListenerInterceptor.java | 2 +- .../interceptor/ExecuteInterceptor.java | 4 +- .../execute/interceptor/ExecutorInvoker.java | 4 +- .../interceptor/FailBackInterceptor.java | 4 +- .../interceptor/FailFastInterceptor.java | 4 +- .../interceptor/FailOverInterceptor.java | 4 +- .../execute/interceptor/LogInterceptor.java | 4 +- .../consumer/AbstractWorkflowListener.java | 2 +- .../consumer/InnerActivityEventListener.java | 2 +- .../consumer/InnerInstanceEventListener.java | 2 +- .../InnerNotificationEventListener.java | 2 +- .../consumer/InnerTaskEventListener.java | 2 +- .../filter/InnerFilterDefinitionKey.java | 32 +++++++++++ .../filter/InnerFilterExtension.java | 20 +++++++ .../filter/InnerFilterMQOwnerShip.java | 44 ++++++++++++++ .../MessageQueueHandleBeforeFilter.java | 15 +++++ 21 files changed, 192 insertions(+), 49 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/ListenerExecutor.java (86%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/AbstractListenerInterceptor.java (82%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/ExecuteInterceptor.java (64%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/ExecutorInvoker.java (79%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/FailBackInterceptor.java (81%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/FailFastInterceptor.java (85%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/FailOverInterceptor.java (93%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{mq => listener}/execute/interceptor/LogInterceptor.java (86%) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java index 2cedf5fe5..5d9bbe2a5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java @@ -68,7 +68,9 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); - newHeaders.put(MQ_OWNERSHIP_APP, applicationName); + // FIXME +// newHeaders.put(MQ_OWNERSHIP_APP, applicationName); + newHeaders.put(MQ_OWNERSHIP_APP, "senna"); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 2f2a7b088..3abc1e620 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -6,18 +6,18 @@ import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.interceptor.ExecuteInterceptor; +import cn.axzo.workflow.starter.listener.execute.interceptor.ExecutorInvoker; +import cn.axzo.workflow.starter.listener.execute.interceptor.FailBackInterceptor; +import cn.axzo.workflow.starter.listener.execute.interceptor.FailFastInterceptor; +import cn.axzo.workflow.starter.listener.execute.interceptor.FailOverInterceptor; +import cn.axzo.workflow.starter.listener.execute.interceptor.LogInterceptor; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; -import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; -import cn.axzo.workflow.starter.mq.execute.interceptor.ExecutorInvoker; -import cn.axzo.workflow.starter.mq.execute.interceptor.FailBackInterceptor; -import cn.axzo.workflow.starter.mq.execute.interceptor.FailFastInterceptor; -import cn.axzo.workflow.starter.mq.execute.interceptor.FailOverInterceptor; -import cn.axzo.workflow.starter.mq.execute.interceptor.LogInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index bba0a7f89..ea63a916e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -12,8 +12,13 @@ import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKey; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; +import cn.axzo.workflow.starter.mq.broadcast.filter.MessageQueueHandleBeforeFilter; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; +import com.google.common.collect.ImmutableList; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; @@ -29,18 +34,16 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; +import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; /** * 配置 RocketMQ 事件监听器 @@ -93,26 +96,32 @@ public class WorkflowEngineStarterRocketMQConfiguration { ) public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); + @Resource(name = "eventConsumer") private EventConsumer eventConsumer; - @Resource - private WorkflowEngineStarterProperties workflowEngineStarterProperties; @Value("${spring.application.name}") private String applicationName; + @Resource + private WorkflowEngineStarterProperties starterProperties; + private List filters; + + @PostConstruct + public void init() { + this.filters = ImmutableList.of( + new InnerFilterMQOwnerShip(starterProperties, applicationName), + new InnerFilterDefinitionKey(starterProperties), + new InnerFilterExtension()); + } @Override public void onMessage(MessageExt message) { - if (workflowEngineStarterProperties.getBroadcast().getEnableFilterApplicationName()) { - Map properties = message.getProperties(); - String mqOwnerShip = properties.getOrDefault(MQ_OWNERSHIP_APP, null); - if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { - super.onEvent(message, eventConsumer); - } else { - log.info("broadcast message not attribution this application, will be ignored. messageId: {}, mq-ownership: {}", message.getMsgId(), mqOwnerShip); + for (MessageQueueHandleBeforeFilter filter : filters) { + if (filter.doFilter(message)) { + log.info("message has been filtered"); + return; } - } else { - super.onEvent(message, eventConsumer); } + super.onEvent(message, eventConsumer); } } @@ -232,21 +241,27 @@ public class WorkflowEngineStarterRocketMQConfiguration { ) public static class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { private final Logger log = LoggerFactory.getLogger(WorkflowEngineClientRetryConsumer.class); + @Resource(name = "workflowEngineStarterEventConsumer") private EventConsumer workflowEngineStarterEventConsumer; @Value("${spring.application.name}") private String applicationName; + @Resource + private WorkflowEngineStarterProperties starterProperties; + private MessageQueueHandleBeforeFilter filter; + + @PostConstruct + public void init() { + this.filter = new InnerFilterMQOwnerShip(starterProperties, applicationName); + } @Override public void onMessage(MessageExt message) { - Map properties = message.getProperties(); - String mqOwnerShip = properties.getOrDefault(MQ_OWNERSHIP_APP, null); - if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { - super.onEvent(message, workflowEngineStarterEventConsumer); - } else { - log.info("rpc retry message not attribution this application, will be ignored. messageId: {}, mq-ownership: {}", message.getMsgId(), mqOwnerShip); + if (filter.doFilter(message)) { + log.info("message has been filtered"); + return; } - + super.onEvent(message, workflowEngineStarterEventConsumer); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java new file mode 100644 index 000000000..b73b353f5 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java @@ -0,0 +1,15 @@ +package cn.axzo.workflow.starter.listener; + +import org.springframework.core.Ordered; + +/** + * TODO + * + * @author wangli + * @since 2024/6/4 17:04 + */ +public interface BroadcastMessageQueueFilter extends Ordered { + + boolean doFilter(); + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/ListenerExecutor.java similarity index 86% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/ListenerExecutor.java index e5a055b32..3f184742e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/ListenerExecutor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/ListenerExecutor.java @@ -1,7 +1,7 @@ -package cn.axzo.workflow.starter.mq.execute; +package cn.axzo.workflow.starter.listener.execute; import cn.axzo.framework.domain.ServiceException; -import cn.axzo.workflow.starter.mq.execute.interceptor.ExecuteInterceptor; +import cn.axzo.workflow.starter.listener.execute.interceptor.ExecuteInterceptor; import java.util.List; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/AbstractListenerInterceptor.java similarity index 82% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/AbstractListenerInterceptor.java index a033812f3..0679bee62 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/AbstractListenerInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/AbstractListenerInterceptor.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; public abstract class AbstractListenerInterceptor implements ExecuteInterceptor { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecuteInterceptor.java similarity index 64% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecuteInterceptor.java index bacc59e73..de6290d70 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecuteInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecuteInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecutorInvoker.java similarity index 79% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecutorInvoker.java index 5cd92acee..eb90f956d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/ExecutorInvoker.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecutorInvoker.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailBackInterceptor.java similarity index 81% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailBackInterceptor.java index fca7356d0..ff84e3873 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailBackInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailBackInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailFastInterceptor.java similarity index 85% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailFastInterceptor.java index 657898731..544059200 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailFastInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailFastInterceptor.java @@ -1,7 +1,7 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; import cn.axzo.workflow.starter.common.exception.WorkflowListenerExeException; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailOverInterceptor.java similarity index 93% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailOverInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailOverInterceptor.java index bd130890b..ff525cba4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailOverInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/LogInterceptor.java similarity index 86% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/LogInterceptor.java index d4d677306..17acfaf74 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/LogInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.mq.execute.interceptor; +package cn.axzo.workflow.starter.listener.execute.interceptor; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StopWatch; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index 7f8030139..e982c676f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -2,7 +2,7 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index c95c2e256..95094aa8a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -5,7 +5,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index e763e45e5..33fe25e7f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -5,7 +5,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java index 8ed0b875a..a7ab9dabe 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java @@ -5,7 +5,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 6d369ef7a..616721d21 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -5,7 +5,7 @@ import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; -import cn.axzo.workflow.starter.mq.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java new file mode 100644 index 000000000..219c4b2fc --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java @@ -0,0 +1,32 @@ +package cn.axzo.workflow.starter.mq.broadcast.filter; + +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * TODO + * + * @author wangli + * @since 2024/6/4 17:06 + */ +public class InnerFilterDefinitionKey implements MessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterDefinitionKey.class); + private final WorkflowEngineStarterProperties properties; + + public InnerFilterDefinitionKey(WorkflowEngineStarterProperties properties) { + this.properties = properties; + } + + @Override + public boolean doFilter(MessageExt message) { + if (!properties.getBroadcast().getEnableFilterDefinitionKey()) { + return false; + } + Map properties = message.getProperties(); + return false; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java new file mode 100644 index 000000000..73f59844e --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java @@ -0,0 +1,20 @@ +package cn.axzo.workflow.starter.mq.broadcast.filter; + +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TODO + * + * @author wangli + * @since 2024/6/4 17:10 + */ +public class InnerFilterExtension implements MessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterExtension.class); + + @Override + public boolean doFilter(MessageExt message) { + return false; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java new file mode 100644 index 000000000..79f4817a1 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java @@ -0,0 +1,44 @@ +package cn.axzo.workflow.starter.mq.broadcast.filter; + +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import org.apache.rocketmq.common.message.MessageExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.util.Map; +import java.util.Objects; + +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; + +/** + * TODO + * + * @author wangli + * @since 2024/6/4 17:06 + */ +public class InnerFilterMQOwnerShip implements MessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterMQOwnerShip.class); + + private final WorkflowEngineStarterProperties properties; + private final String applicationName; + + public InnerFilterMQOwnerShip(WorkflowEngineStarterProperties properties, String applicationName) { + this.properties = properties; + this.applicationName = applicationName; + } + + @Override + public boolean doFilter(MessageExt message) { + if (!properties.getBroadcast().getEnableFilterApplicationName()) { + return false; + } + Map properties = message.getProperties(); + String mqOwnerShip = properties.getOrDefault(MQ_OWNERSHIP_APP, null); + if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { + return false; + } + log.info("broadcast message not attribution this application, will be ignored. messageId: {}, mq-ownership: {}", message.getMsgId(), mqOwnerShip); + return true; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java new file mode 100644 index 000000000..fb2448a1e --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java @@ -0,0 +1,15 @@ +package cn.axzo.workflow.starter.mq.broadcast.filter; + +import org.apache.rocketmq.common.message.MessageExt; + +/** + * TODO + * + * @author wangli + * @since 2024/6/4 17:12 + */ +public interface MessageQueueHandleBeforeFilter { + + boolean doFilter(MessageExt message); + +} From 51435465f6b3a1cd0fe623149e7996fad77c3e3e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 18:44:37 +0800 Subject: [PATCH 067/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E5=BC=95=E6=93=8E=E6=9C=8D=E5=8A=A1=E7=AB=AF=E5=8F=91?= =?UTF-8?q?=E5=87=BA=E4=BA=8B=E4=BB=B6=E4=B8=AD=20targetId=20=E4=B8=BA=20p?= =?UTF-8?q?rocessDefinitionKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/model/response/mq/ProcessTaskDTO.java | 7 +++++++ .../activity/RocketMqBpmActivityEventListener.java | 2 +- .../listener/notice/RocketMqMessagePushEventListener.java | 2 +- .../listener/process/RocketMqBpmnProcessEventListener.java | 2 +- .../listener/task/RocketMqBpmnTaskEvent_102_Listener.java | 6 ++++-- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java index a3db4b04c..0dfef6a2f 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java @@ -28,8 +28,11 @@ public class ProcessTaskDTO implements Serializable { private ProcessTaskEventEnum type; /** + * 请使用 {@link ProcessTaskDTO#processDefinitionKey} 代替访问此属性,未来将逐步废弃 + *

* 流程实例所属业务分类,同时也等于流程模型对应的业务分类 ID */ + @Deprecated private String category; /** @@ -41,6 +44,10 @@ public class ProcessTaskDTO implements Serializable { * 流程实例 ID */ private String processInstanceId; + /** + * 流程实例所属业务分类,同时也等于流程模型对应的业务分类 ID + */ + private String processDefinitionKey; /** * 流程定义中当前任务节点 Key diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java index 1da62614e..49f202666 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java @@ -182,7 +182,7 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener< eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessInstanceId()) + .targetId(dto.getProcessDefinitionKey()) .targetType(eventEnum.getTag()) .data(dto) .build()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java index 42d5e652a..d58f4c073 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java @@ -392,7 +392,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener< eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessInstanceId()) + .targetId(dto.getProcessDefinitionKey()) .targetType(eventEnum.getTag()) .data(dto) .build()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java index 8fb08ab17..81a360b9a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java @@ -274,7 +274,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener< eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessInstanceId()) + .targetId(dto.getProcessDefinitionKey()) .targetType(eventEnum.getTag()) .data(dto) .build()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index 355dbd01d..eaac29192 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -103,9 +103,11 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene public ProcessTaskDTO build(DelegateTask delegateTask, ProcessTaskEventEnum type) { Process mainProcess = getContext().getProcess(() -> repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()).getMainProcess()); + String category = getDeployment(delegateTask.getProcessInstanceId()).getCategory(); ProcessTaskDTO dto = new ProcessTaskDTO() .setType(type) - .setCategory(getDeployment(delegateTask.getProcessInstanceId()).getCategory()) + .setCategory(category) + .setProcessDefinitionKey(category) .setProcessTaskId(delegateTask.getId()) .setProcessInstanceId(delegateTask.getProcessInstanceId()) .setCurrentElementKey(delegateTask.getTaskDefinitionKey()) @@ -134,7 +136,7 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessInstanceId()) + .targetId(dto.getProcessDefinitionKey()) .targetType(eventEnum.getTag()) .data(dto) .build()); From 38a099cb111c93362fd41ea3efbba0105716bd75 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Jun 2024 19:10:49 +0800 Subject: [PATCH 068/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20MQ=20=E4=BA=8B=E4=BB=B6=E5=A2=9E=E5=8A=A0=20process?= =?UTF-8?q?DefinitionKey=20=E5=B1=9E=E6=80=A7=EF=BC=8C=20=E6=9C=AA?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/response/mq/MessagePushDTO.java | 5 +++ .../core/engine/event/MessagePushEvent.java | 2 + .../engine/event/MessagePushEventBuilder.java | 44 +++++++++++-------- .../engine/event/MessagePushEventImpl.java | 16 ++++++- .../EngineCarbonCopyEventListener.java | 2 + .../EngineProcessInstanceEventListener.java | 3 +- .../listener/AbstractBpmnEventListener.java | 8 ++++ .../impl/BpmnProcessTaskServiceImpl.java | 1 + .../ApproveErrorReporterEventListener.java | 5 ++- .../RocketMqMessagePushEventListener.java | 1 + .../MessagePushProcessEventListener.java | 4 +- .../MessagePushTaskEvent_103_Listener.java | 6 ++- 12 files changed, 71 insertions(+), 26 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/MessagePushDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/MessagePushDTO.java index 95f97ab77..04a5e0d79 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/MessagePushDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/MessagePushDTO.java @@ -31,6 +31,11 @@ public class MessagePushDTO implements Serializable { */ private String processInstanceId; + /** + * 业务 ID + */ + private String processDefinitionKey; + /** * 流程任务 ID */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEvent.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEvent.java index 1af8582a1..6f57f3383 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEvent.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEvent.java @@ -25,6 +25,8 @@ public interface MessagePushEvent extends FlowableEvent { String getProcessDefinitionId(); + String getProcessDefinitionKey(); + String getCurrentTaskDefinitionKey(); String getTenantId(); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java index f3c11e84a..0fbea9e20 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java @@ -26,21 +26,21 @@ import static cn.axzo.workflow.core.engine.event.MessagePushEventType.SMS; public class MessagePushEventBuilder { public static MessagePushEventImpl createEvent(MessagePushEventType type, List assigners, - BpmnNoticeConf noticeConf, String processInstanceId, + BpmnNoticeConf noticeConf, String processInstanceId, String processDefinitionKey, String tenantId, String taskId) { switch (type) { case NOTICE: - return createNoticeEvent(assigners, noticeConf, processInstanceId, tenantId, taskId); + return createNoticeEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId); case PENDING_PUSH: throw new WorkflowEngineException(MESSAGE_PUSH_EVENT_BUILD_ERROR); case PENDING_COMPLETE: - return createPendingCompleteEvent(assigners, noticeConf, processInstanceId, tenantId, taskId); + return createPendingCompleteEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId); case CARBON_COPY: - return createCarbonCopyEvent(assigners, noticeConf, processInstanceId, tenantId); + return createCarbonCopyEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId); case CARBON_COPY_COMPLETE: - return createCarbonCopyCompleteEvent(assigners, noticeConf, processInstanceId, tenantId); + return createCarbonCopyCompleteEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId); case SMS: - return createSmsEvent(assigners, noticeConf, processInstanceId, tenantId, taskId); + return createSmsEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId); default: throw new WorkflowEngineException(MES_PUSH_OBJECT_BUILD_ERROR); } @@ -48,9 +48,9 @@ public class MessagePushEventBuilder { public static MessagePushEventImpl createNoticeEvent(List assigners, BpmnNoticeConf noticeConf - , String processInstanceId, String tenantId, String taskId) { + , String processInstanceId, String processDefinitionKey, String tenantId, String taskId) { MessagePushEventImpl newEvent = new MessagePushEventImpl(NOTICE, assigners, noticeConf, processInstanceId, - tenantId, taskId); + processDefinitionKey, tenantId, taskId); return newEvent; } @@ -58,47 +58,55 @@ public class MessagePushEventBuilder { BpmnNoticeConf noticeConf, BpmnApproveConf processApproveConf, String processInstanceId, - String processDefinitionId, String currentTaskDefinitionKey, + String processDefinitionId, + String processDefinitionKey, + String currentTaskDefinitionKey, String tenantId, String taskId) { - MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_PUSH, assigners, noticeConf, processApproveConf, processInstanceId, - processDefinitionId, currentTaskDefinitionKey, tenantId, taskId); + MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_PUSH, assigners, noticeConf, processApproveConf, + processInstanceId, processDefinitionId, processDefinitionKey, currentTaskDefinitionKey, tenantId, taskId); return newEvent; } public static MessagePushEventImpl createPendingCompleteEvent(List assigners, BpmnNoticeConf noticeConf, String processInstanceId, + String processDefinitionKey, String tenantId, String taskId) { MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_COMPLETE, assigners, noticeConf, - processInstanceId, + processInstanceId, processDefinitionKey, tenantId, taskId); return newEvent; } - public static MessagePushEvent createPendingRollbackEvent(String processInstanceId, String tenantId, String taskId, BpmnNoticeConf noticeConf) { - return new MessagePushEventImpl(PENDING_ROLLBACK, null, noticeConf, processInstanceId, tenantId, taskId); + public static MessagePushEvent createPendingRollbackEvent(String processInstanceId, String processDefinitionKey, + String tenantId, String taskId, BpmnNoticeConf noticeConf) { + return new MessagePushEventImpl(PENDING_ROLLBACK, null, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId); } public static MessagePushEventImpl createCarbonCopyEvent(List assigners, BpmnNoticeConf noticeConf, String processInstanceId, + String processDefinitionKey, String tenantId) { MessagePushEventImpl newEvent = new MessagePushEventImpl(CARBON_COPY, assigners, noticeConf, - processInstanceId, tenantId, null); + processInstanceId, processDefinitionKey, tenantId, null); return newEvent; } public static MessagePushEventImpl createCarbonCopyCompleteEvent(List assigners, BpmnNoticeConf noticeConf, String processInstanceId, + String processDefinitionKey, String tenantId) { MessagePushEventImpl newEvent = new MessagePushEventImpl(CARBON_COPY_COMPLETE, assigners, noticeConf, - processInstanceId, tenantId, null); + processInstanceId, processDefinitionKey, tenantId, null); return newEvent; } public static MessagePushEventImpl createSmsEvent(List assigners, BpmnNoticeConf noticeConf, - String processInstanceId, String tenantId, String taskId) { + String processInstanceId, + String processDefinitionKey, + String tenantId, String taskId) { MessagePushEventImpl newEvent = new MessagePushEventImpl(SMS, assigners, noticeConf, processInstanceId, - tenantId, taskId); + processDefinitionKey, tenantId, taskId); return newEvent; } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventImpl.java index 98bf4dc09..d6eabf517 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventImpl.java @@ -25,6 +25,7 @@ public class MessagePushEventImpl implements MessagePushEvent { private BpmnApproveConf processApproveConfig; private String processInstanceId; private String processDefinitionId; + private String processDefinitionKey; private String currentTaskDefinitionKey; private String tenantId; private String taskId; @@ -48,11 +49,13 @@ public class MessagePushEventImpl implements MessagePushEvent { * @param tenantId * @param taskId */ - public MessagePushEventImpl(FlowableEventType type, List assigners, BpmnNoticeConf noticeConfig, String processInstanceId, String tenantId, String taskId) { + public MessagePushEventImpl(FlowableEventType type, List assigners, BpmnNoticeConf noticeConfig, + String processInstanceId, String processDefinitionKey, String tenantId, String taskId) { this.type = type; this.assigners = assigners; this.noticeConfig = noticeConfig; this.processInstanceId = processInstanceId; + this.processDefinitionKey = processDefinitionKey; this.tenantId = tenantId; this.taskId = taskId; } @@ -75,7 +78,7 @@ public class MessagePushEventImpl implements MessagePushEvent { public MessagePushEventImpl(FlowableEventType type, List assigners, BpmnNoticeConf noticeConfig, BpmnApproveConf processApproveConfig, - String processInstanceId, String processDefinitionId, + String processInstanceId, String processDefinitionId, String processDefinitionKey, String currentTaskDefinitionKey, String tenantId, String taskId) { this.type = type; this.assigners = assigners; @@ -141,6 +144,15 @@ public class MessagePushEventImpl implements MessagePushEvent { this.processDefinitionId = processDefinitionId; } + @Override + public String getProcessDefinitionKey() { + return processDefinitionKey; + } + + public void setProcessDefinitionKey(String processDefinitionKey) { + this.processDefinitionKey = processDefinitionKey; + } + @Override public String getCurrentTaskDefinitionKey() { return currentTaskDefinitionKey; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineCarbonCopyEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineCarbonCopyEventListener.java index c9f26d948..47d9a3cae 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineCarbonCopyEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineCarbonCopyEventListener.java @@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicReference; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCarbonCopyConfigs; +import static cn.axzo.workflow.core.listener.AbstractBpmnEventListener.parseProcessDefinitionKey; /** * 抄送功能的具体实现 @@ -110,6 +111,7 @@ public class EngineCarbonCopyEventListener implements JavaDelegate { MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.CARBON_COPY, carbonUsers, bpmnNoticeConf, execution.getProcessInstanceId(), + parseProcessDefinitionKey(execution.getProcessDefinitionId()), execution.getTenantId(), getCarbonTaskId(execution)); eventDispatcher.dispatchEvent(event, processEngineConfiguration.getEngineCfgKey()); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java index 8a0073440..c27afe2e0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java @@ -158,7 +158,8 @@ public class EngineProcessInstanceEventListener extends AbstractFlowableEngineEv .execute(new CustomNoticeDestinationUserSelectorCmd(engineExecutionStartListener, historicTaskInstanceConverter, serviceVersion, workspaceType, config.getNotice(), event.getProcessInstanceId(), assigner)); MessagePushEventImpl messagePushEvent = MessagePushEventBuilder.createEvent(MessagePushEventType.NOTICE, - assigners, config, processInstance.getProcessInstanceId(), processInstance.getTenantId(), null); + assigners, config, processInstance.getProcessInstanceId(), processInstance.getProcessDefinitionKey(), + processInstance.getTenantId(), null); log.info("发送通知消息: {}", JSONUtil.toJsonStr(messagePushEvent)); eventDispatcher.dispatchEvent(messagePushEvent, processEngineConfiguration.getEngineCfgKey()); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java index 63399b2ec..5fa245c7d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.listener; import cn.axzo.workflow.core.common.context.OperationContext; import cn.hutool.json.JSONUtil; import org.slf4j.MDC; +import org.springframework.util.StringUtils; import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; @@ -33,4 +34,11 @@ public abstract class AbstractBpmnEventListener impl protected String buildCacheKey(String apiUrl, Object request) { return apiUrl + JSONUtil.toJsonStr(request); } + + public static String parseProcessDefinitionKey(String processDefinitionId) { + if (StringUtils.hasText(processDefinitionId)) { + return ""; + } + return processDefinitionId.split(":")[0]; + } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 5eb112cf3..86f7d06f8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -628,6 +628,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.valueOf(type), Lists.newArrayList(assigner), noticeConfig.orElse(null), processInstance.getProcessInstanceId(), + processInstance.getProcessDefinitionKey(), processInstance.getTenantId(), task.getId()); event.setProcessInstanceId(processInstance.getProcessInstanceId()); event.setTenantId(processInstance.getTenantId()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ApproveErrorReporterEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ApproveErrorReporterEventListener.java index 501ae8c5e..0f684ac04 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ApproveErrorReporterEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ApproveErrorReporterEventListener.java @@ -31,6 +31,7 @@ import java.util.Optional; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE; +import static cn.axzo.workflow.core.listener.AbstractBpmnEventListener.parseProcessDefinitionKey; import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.JOB_MOVED_TO_DEADLETTER; /** @@ -80,7 +81,9 @@ public class ApproveErrorReporterEventListener implements BpmnAsyncJobEventListe Optional noticeConfig = BpmnMetaParserHelper.getNoticeConfig(process); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); - MessagePushEvent event = MessagePushEventBuilder.createPendingRollbackEvent(jobEvent.getProcessInstanceId(), jobInfo.getTenantId(), dto.getTaskId(), noticeConfig.orElse(new BpmnNoticeConf())); + MessagePushEvent event = MessagePushEventBuilder.createPendingRollbackEvent(jobEvent.getProcessInstanceId(), + parseProcessDefinitionKey(jobEvent.getProcessDefinitionId()), + jobInfo.getTenantId(), dto.getTaskId(), noticeConfig.orElse(new BpmnNoticeConf())); log.info("发送恢复待办的流程事件消息: taskDto:{},event:{}", JSONUtil.toJsonStr(dto), JSONUtil.toJsonStr(event)); eventDispatcher.dispatchEvent(event, processEngineConfiguration.getEngineCfgKey()); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java index d58f4c073..3bed16c49 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java @@ -376,6 +376,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener< Object> variables) { return new MessagePushDTO() .setProcessInstanceId(event.getProcessInstanceId()) + .setProcessDefinitionKey(event.getProcessDefinitionKey()) .setType(type) .setTemplateId(templateId) .setTaskId(event.getTaskId()) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/MessagePushProcessEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/MessagePushProcessEventListener.java index 81cc92bb9..75660f280 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/MessagePushProcessEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/MessagePushProcessEventListener.java @@ -76,7 +76,7 @@ public class MessagePushProcessEventListener extends AbstractBpmnEventListener

{ MessagePushEventImpl messagePushEvent = MessagePushEventBuilder.createEvent(MessagePushEventType.PENDING_COMPLETE, null, noticeConfig, - event.getProcessInstanceId(), null, null); + event.getProcessInstanceId(), parseProcessDefinitionKey(event.getProcessDefinitionId()), null, null); log.info("发送完成实例下所有待办的消息: {}", JSONUtil.toJsonStr(messagePushEvent)); @@ -87,7 +87,7 @@ public class MessagePushProcessEventListener extends AbstractBpmnEventListener

Date: Tue, 4 Jun 2024 23:15:50 +0800 Subject: [PATCH 069/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=B9=BF=E6=92=AD=E6=B6=88=E6=81=AF,=E5=9C=A8=20Start?= =?UTF-8?q?er=20=E4=B8=AD=E7=9A=84=E4=B8=BB=E5=8A=A8=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/constant/BpmnConstants.java | 3 ++- .../engine/event/MessagePushEventBuilder.java | 3 +-- .../EngineProcessInstanceEventListener.java | 4 ++-- .../core/mq/CustomRocketMQEventProducer.java | 4 ++-- .../RocketMqBpmActivityEventListener.java | 11 ++++++++--- .../notice/RocketMqMessagePushEventListener.java | 9 ++++++--- .../RocketMqBpmnProcessEventListener.java | 11 ++++++++--- .../task/RocketMqBpmnTaskEvent_102_Listener.java | 11 ++++++++--- ...BroadcastListenerConfigurationProperties.java | 2 ++ .../filter/InnerFilterDefinitionKey.java | 16 ++++++++++++++-- .../broadcast/filter/InnerFilterMQOwnerShip.java | 8 ++++---- .../filter/MessageQueueHandleBeforeFilter.java | 8 +++++++- .../retry/producer/RpcInvokeEventProducer.java | 4 ++-- 13 files changed, 66 insertions(+), 28 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 69865ff76..ffdd11d80 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -154,5 +154,6 @@ public interface BpmnConstants { /** * 用于 MQ 的 Header, 记录当前事件的归属应用 */ - String MQ_OWNERSHIP_APP = "MQ_OWNERSHIP_APPLICATION"; + String MQ_OWNERSHIP_APPLICATION = "MQ_OWNERSHIP_APPLICATION"; + String MQ_OWNERSHIP_PROCESS_DEFINITION_KEY = "MQ_OWNERSHIP_PROCESS_DEFINITION_KEY"; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java index 0fbea9e20..a6ffc9439 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/event/MessagePushEventBuilder.java @@ -72,8 +72,7 @@ public class MessagePushEventBuilder { String processDefinitionKey, String tenantId, String taskId) { MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_COMPLETE, assigners, noticeConf, - processInstanceId, processDefinitionKey, - tenantId, taskId); + processInstanceId, processDefinitionKey, tenantId, taskId); return newEvent; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java index c27afe2e0..25aa3d6ba 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineProcessInstanceEventListener.java @@ -8,7 +8,6 @@ import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.engine.cmd.CustomNoticeDestinationUserSelectorCmd; import cn.axzo.workflow.core.engine.event.MessagePushEventBuilder; import cn.axzo.workflow.core.engine.event.MessagePushEventImpl; -import cn.axzo.workflow.core.engine.event.MessagePushEventType; import cn.axzo.workflow.core.listener.BpmnProcessEventListener; import cn.axzo.workflow.core.service.converter.BpmnHistoricTaskInstanceConverter; import cn.hutool.json.JSONUtil; @@ -48,6 +47,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROV import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCELLED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; +import static cn.axzo.workflow.core.engine.event.MessagePushEventType.NOTICE; /** * 引擎全局的流程实例事件监听 @@ -157,7 +157,7 @@ public class EngineProcessInstanceEventListener extends AbstractFlowableEngineEv List assigners = processEngineConfiguration.getCommandExecutor() .execute(new CustomNoticeDestinationUserSelectorCmd(engineExecutionStartListener, historicTaskInstanceConverter, serviceVersion, workspaceType, config.getNotice(), event.getProcessInstanceId(), assigner)); - MessagePushEventImpl messagePushEvent = MessagePushEventBuilder.createEvent(MessagePushEventType.NOTICE, + MessagePushEventImpl messagePushEvent = MessagePushEventBuilder.createEvent(NOTICE, assigners, config, processInstance.getProcessInstanceId(), processInstance.getProcessDefinitionKey(), processInstance.getTenantId(), null); log.info("发送通知消息: {}", JSONUtil.toJsonStr(messagePushEvent)); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java index 5d9bbe2a5..fe9e54118 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java @@ -17,7 +17,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION; /** * 默认的 RocketMQ 事件生产者的装饰器 @@ -70,7 +70,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); // FIXME // newHeaders.put(MQ_OWNERSHIP_APP, applicationName); - newHeaders.put(MQ_OWNERSHIP_APP, "senna"); + newHeaders.put(MQ_OWNERSHIP_APPLICATION, "senna"); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java index 49f202666..27abc8004 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java @@ -28,12 +28,15 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.ProcessActivityEventEnum.PROCESS_ACTIVITY_END; @@ -179,13 +182,15 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener< if (!sendMQ) { return; } + Map header = new HashMap<>(); + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessDefinitionKey()) - .targetType(eventEnum.getTag()) + .targetId(dto.getProcessInstanceId()) + .targetType(dto.getProcessDefinitionKey()) .data(dto) - .build()); + .build(), header); } @Override diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java index 3bed16c49..5b216ebfe 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java @@ -54,6 +54,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TY import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER; import static cn.axzo.workflow.common.constant.BpmnConstants.NUMBER_OF_INSTANCES; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; @@ -390,13 +391,15 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener< if (!sendMQ) { return; } + Map header = new HashMap<>(); + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessDefinitionKey()) - .targetType(eventEnum.getTag()) + .targetId(dto.getProcessInstanceId()) + .targetType(dto.getProcessDefinitionKey()) .data(dto) - .build()); + .build(), header); } @Override diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java index 81a360b9a..0b823bc06 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java @@ -25,11 +25,14 @@ import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_DELETE_REASON; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_ABORTED; import static cn.axzo.workflow.common.enums.ProcessInstanceEventEnum.PROCESS_INSTANCE_CANCELLED; @@ -271,13 +274,15 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener< if (!sendMQ) { return; } + Map header = new HashMap<>(); + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessDefinitionKey()) - .targetType(eventEnum.getTag()) + .targetId(dto.getProcessInstanceId()) + .targetType(dto.getProcessDefinitionKey()) .data(dto) - .build()); + .build(), header); } @Override diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index eaac29192..8a85e4fc5 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -23,11 +23,14 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED; @@ -133,13 +136,15 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene if (!sendMQ) { return; } + Map header = new HashMap<>(); + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessDefinitionKey()) - .targetType(eventEnum.getTag()) + .targetId(dto.getProcessInstanceId()) + .targetType(dto.getProcessDefinitionKey()) .data(dto) - .build()); + .build(), header); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java index 7fd0a1dd0..28894bdfc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java @@ -31,6 +31,8 @@ public class BroadcastListenerConfigurationProperties { * 过滤出 MQ 事件中包含这些业务 ID 的事件 *

* 只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效 + *

+ * 注意: 如果 enableFilterDefinitionKey = true,但该属性集合为空, 将不会过滤任何消息 */ private Set filterProcessDefinitionKeys = new HashSet<>(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java index 219c4b2fc..847d37ed2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java @@ -4,9 +4,12 @@ import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; import java.util.Map; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; + /** * TODO * @@ -26,7 +29,16 @@ public class InnerFilterDefinitionKey implements MessageQueueHandleBeforeFilter if (!properties.getBroadcast().getEnableFilterDefinitionKey()) { return false; } - Map properties = message.getProperties(); - return false; + if (CollectionUtils.isEmpty(properties.getBroadcast().getFilterProcessDefinitionKeys())) { + log.warn("Your system has the filter process-definition-key enabled, but `BroadcastListenerConfigurationProperties.filterProcessDefinitionKeys` is empty"); + return false; + } + Map headers = message.getProperties(); + String processDefinitionKey = headers.getOrDefault(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, ""); + if (properties.getBroadcast().getFilterProcessDefinitionKeys().contains(processDefinitionKey)) { + return false; + } + log.info("The broadcast message does not belong to the key of interest, will be ignored. messageId: {}, message process-definition-key: {}", message.getMsgId(), processDefinitionKey); + return true; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java index 79f4817a1..d5995de0a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java @@ -9,7 +9,7 @@ import org.springframework.util.StringUtils; import java.util.Map; import java.util.Objects; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION; /** * TODO @@ -33,12 +33,12 @@ public class InnerFilterMQOwnerShip implements MessageQueueHandleBeforeFilter { if (!properties.getBroadcast().getEnableFilterApplicationName()) { return false; } - Map properties = message.getProperties(); - String mqOwnerShip = properties.getOrDefault(MQ_OWNERSHIP_APP, null); + Map headers = message.getProperties(); + String mqOwnerShip = headers.getOrDefault(MQ_OWNERSHIP_APPLICATION, null); if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { return false; } - log.info("broadcast message not attribution this application, will be ignored. messageId: {}, mq-ownership: {}", message.getMsgId(), mqOwnerShip); + log.info("The broadcast message does not attribute the message, will be ignored. messageId: {}, mq-ownership-application: {}", message.getMsgId(), mqOwnerShip); return true; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java index fb2448a1e..d23551755 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java @@ -3,13 +3,19 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; import org.apache.rocketmq.common.message.MessageExt; /** - * TODO + * 过滤 MQ 消息, 不再对其进行消费 * * @author wangli * @since 2024/6/4 17:12 */ public interface MessageQueueHandleBeforeFilter { + /** + * 传入 RocketMQ 底层的消息对象,对消费过程中的消息过滤 + * + * @param message + * @return 为 true 时,代表需要被过滤 + */ boolean doFilter(MessageExt message); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index fc5954a89..a28fc4e61 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; +import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION; /** * RPC 的调用动作的 MQ 事件生产者 @@ -71,7 +71,7 @@ public class RpcInvokeEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); - newHeaders.put(MQ_OWNERSHIP_APP, applicationName); + newHeaders.put(MQ_OWNERSHIP_APPLICATION, applicationName); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { From 535c482fd7959311aab57e3280c91b8fb51851c5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Jun 2024 11:38:11 +0800 Subject: [PATCH 070/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=BA?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E5=8F=AF=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E7=9A=84=20MQ=20=E4=BA=8B=E4=BB=B6=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...lowEngineStarterRocketMQConfiguration.java | 24 ++++++++------ .../listener/BroadcastMessageQueueFilter.java | 10 ++++-- ...ava => InnerFilterDefinitionKeyInner.java} | 6 ++-- .../filter/InnerFilterExtension.java | 32 +++++++++++++++++-- ....java => InnerFilterMQOwnerShipInner.java} | 6 ++-- ... InnerMessageQueueHandleBeforeFilter.java} | 2 +- 6 files changed, 59 insertions(+), 21 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/{InnerFilterDefinitionKey.java => InnerFilterDefinitionKeyInner.java} (88%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/{InnerFilterMQOwnerShip.java => InnerFilterMQOwnerShipInner.java} (86%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/{MessageQueueHandleBeforeFilter.java => InnerMessageQueueHandleBeforeFilter.java} (88%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index ea63a916e..4b8e2107d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -10,12 +10,13 @@ import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; +import cn.axzo.workflow.starter.listener.BroadcastMessageQueueFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKey; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKeyInner; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; -import cn.axzo.workflow.starter.mq.broadcast.filter.MessageQueueHandleBeforeFilter; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShipInner; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import com.google.common.collect.ImmutableList; @@ -26,6 +27,7 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -103,19 +105,21 @@ public class WorkflowEngineStarterRocketMQConfiguration { private String applicationName; @Resource private WorkflowEngineStarterProperties starterProperties; - private List filters; + @Resource + private ObjectProvider> businessFilterProvider; + private List filters; @PostConstruct public void init() { this.filters = ImmutableList.of( - new InnerFilterMQOwnerShip(starterProperties, applicationName), - new InnerFilterDefinitionKey(starterProperties), - new InnerFilterExtension()); + new InnerFilterMQOwnerShipInner(starterProperties, applicationName), + new InnerFilterDefinitionKeyInner(starterProperties), + new InnerFilterExtension(businessFilterProvider)); } @Override public void onMessage(MessageExt message) { - for (MessageQueueHandleBeforeFilter filter : filters) { + for (InnerMessageQueueHandleBeforeFilter filter : filters) { if (filter.doFilter(message)) { log.info("message has been filtered"); return; @@ -248,11 +252,11 @@ public class WorkflowEngineStarterRocketMQConfiguration { private String applicationName; @Resource private WorkflowEngineStarterProperties starterProperties; - private MessageQueueHandleBeforeFilter filter; + private InnerMessageQueueHandleBeforeFilter filter; @PostConstruct public void init() { - this.filter = new InnerFilterMQOwnerShip(starterProperties, applicationName); + this.filter = new InnerFilterMQOwnerShipInner(starterProperties, applicationName); } @Override diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java index b73b353f5..464e57b41 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java @@ -1,15 +1,21 @@ package cn.axzo.workflow.starter.listener; +import org.apache.rocketmq.common.message.MessageExt; import org.springframework.core.Ordered; /** - * TODO + * 业务可扩展的 MQ 消息过滤规则 * * @author wangli * @since 2024/6/4 17:04 */ public interface BroadcastMessageQueueFilter extends Ordered { - boolean doFilter(); + /** + * @param message MQ 消息元数据 + * @param jsonData MQ 消息中的 payload,是 JSON 格式的字符串,自行转成对应对象 + * @return + */ + boolean doFilter(MessageExt message, String jsonData); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java similarity index 88% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java index 847d37ed2..316400eba 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java @@ -16,11 +16,11 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCES * @author wangli * @since 2024/6/4 17:06 */ -public class InnerFilterDefinitionKey implements MessageQueueHandleBeforeFilter { - private final Logger log = LoggerFactory.getLogger(InnerFilterDefinitionKey.class); +public class InnerFilterDefinitionKeyInner implements InnerMessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterDefinitionKeyInner.class); private final WorkflowEngineStarterProperties properties; - public InnerFilterDefinitionKey(WorkflowEngineStarterProperties properties) { + public InnerFilterDefinitionKeyInner(WorkflowEngineStarterProperties properties) { this.properties = properties; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java index 73f59844e..eb4146d46 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java @@ -1,20 +1,48 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; +import cn.axzo.workflow.starter.listener.BroadcastMessageQueueFilter; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.core.Ordered; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import static java.nio.charset.StandardCharsets.UTF_8; /** - * TODO + * 用于扩展业务自己的 MQ 事件过滤器 * * @author wangli * @since 2024/6/4 17:10 */ -public class InnerFilterExtension implements MessageQueueHandleBeforeFilter { +public class InnerFilterExtension implements InnerMessageQueueHandleBeforeFilter { private final Logger log = LoggerFactory.getLogger(InnerFilterExtension.class); + private final List businessFilters; + + public InnerFilterExtension(ObjectProvider> businessFilterProvider) { + this.businessFilters = businessFilterProvider.getIfAvailable(Collections::emptyList) + .stream().sorted(Comparator.comparing(Ordered::getOrder)) + .collect(Collectors.toList()); + } + @Override public boolean doFilter(MessageExt message) { + if (businessFilters.isEmpty()) { + log.debug("business filter is empty"); + return false; + } + for (BroadcastMessageQueueFilter businessFilter : businessFilters) { + if (businessFilter.doFilter(message, new String(message.getBody(), UTF_8))) { + return true; + } + } return false; } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShipInner.java similarity index 86% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShipInner.java index d5995de0a..e68a4f9ee 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShipInner.java @@ -17,13 +17,13 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLIC * @author wangli * @since 2024/6/4 17:06 */ -public class InnerFilterMQOwnerShip implements MessageQueueHandleBeforeFilter { - private final Logger log = LoggerFactory.getLogger(InnerFilterMQOwnerShip.class); +public class InnerFilterMQOwnerShipInner implements InnerMessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterMQOwnerShipInner.class); private final WorkflowEngineStarterProperties properties; private final String applicationName; - public InnerFilterMQOwnerShip(WorkflowEngineStarterProperties properties, String applicationName) { + public InnerFilterMQOwnerShipInner(WorkflowEngineStarterProperties properties, String applicationName) { this.properties = properties; this.applicationName = applicationName; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerMessageQueueHandleBeforeFilter.java similarity index 88% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerMessageQueueHandleBeforeFilter.java index d23551755..454e1617f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/MessageQueueHandleBeforeFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerMessageQueueHandleBeforeFilter.java @@ -8,7 +8,7 @@ import org.apache.rocketmq.common.message.MessageExt; * @author wangli * @since 2024/6/4 17:12 */ -public interface MessageQueueHandleBeforeFilter { +public interface InnerMessageQueueHandleBeforeFilter { /** * 传入 RocketMQ 底层的消息对象,对消费过程中的消息过滤 From ab446e926c908455c17974017d306eba91fc176b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Jun 2024 16:30:18 +0800 Subject: [PATCH 071/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=85=B7=E4=BD=93=E7=9A=84=20EventCode=20module=20?= =?UTF-8?q?=E4=B8=8B=E7=9A=84=E4=BA=8B=E4=BB=B6=E8=BF=87=E6=BB=A4=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 24 ++++++---- ...lowEngineStarterRocketMQConfiguration.java | 2 +- .../ext/WorkflowEngineStarterDecoder.java | 2 +- ...rkflowEngineStarterFeignConfiguration.java | 15 +++++- .../MessageNotificationEventFilter.java | 13 ++++++ .../filter/ProcessActivityEventFilter.java | 13 ++++++ .../filter/ProcessInstanceEventFilter.java | 13 ++++++ .../filter/ProcessTaskEventFilter.java | 13 ++++++ .../global}/BroadcastMessageQueueFilter.java | 8 ++-- .../consumer/AbstractWorkflowListener.java | 46 +++++++++++++------ .../consumer/InnerActivityEventListener.java | 17 +++++-- .../consumer/InnerInstanceEventListener.java | 17 +++++-- .../InnerNotificationEventListener.java | 15 ++++-- .../consumer/InnerTaskEventListener.java | 15 ++++-- .../filter/BasicMessageQueueFilter.java | 24 ++++++++++ .../filter/InnerFilterExtension.java | 25 +++++++++- 16 files changed, 212 insertions(+), 50 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/{ => filter/global}/BroadcastMessageQueueFilter.java (58%) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 3abc1e620..8f64dddf2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -13,6 +13,10 @@ import cn.axzo.workflow.starter.listener.execute.interceptor.FailBackInterceptor import cn.axzo.workflow.starter.listener.execute.interceptor.FailFastInterceptor; import cn.axzo.workflow.starter.listener.execute.interceptor.FailOverInterceptor; import cn.axzo.workflow.starter.listener.execute.interceptor.LogInterceptor; +import cn.axzo.workflow.starter.listener.filter.MessageNotificationEventFilter; +import cn.axzo.workflow.starter.listener.filter.ProcessActivityEventFilter; +import cn.axzo.workflow.starter.listener.filter.ProcessInstanceEventFilter; +import cn.axzo.workflow.starter.listener.filter.ProcessTaskEventFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; @@ -59,26 +63,30 @@ public class WorkflowEngineStarterAutoConfiguration { @Bean public WorkflowListener innerProcessEventListener(ListenerExecutor executor, - ObjectProvider> provider) { - return new InnerInstanceEventListener(executor, provider); + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { + return new InnerInstanceEventListener(executor, handlerProvider, filterProvider); } @Bean public WorkflowListener innerActivityEventListener(ListenerExecutor executor, - ObjectProvider> provider) { - return new InnerActivityEventListener(executor, provider); + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { + return new InnerActivityEventListener(executor, handlerProvider, filterProvider); } @Bean public WorkflowListener innerTaskEventListener(ListenerExecutor executor, - ObjectProvider> provider) { - return new InnerTaskEventListener(executor, provider); + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { + return new InnerTaskEventListener(executor, handlerProvider, filterProvider); } @Bean public WorkflowListener innerNotificationEventListener(ListenerExecutor executor, - ObjectProvider> provider) { - return new InnerNotificationEventListener(executor, provider); + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { + return new InnerNotificationEventListener(executor, handlerProvider, filterProvider); } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index 4b8e2107d..02f46130e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -10,7 +10,7 @@ import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; -import cn.axzo.workflow.starter.listener.BroadcastMessageQueueFilter; +import cn.axzo.workflow.starter.listener.filter.global.BroadcastMessageQueueFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKeyInner; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 276d9d18a..c2f920b23 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -67,7 +67,7 @@ final class WorkflowEngineStarterDecoder implements Decoder { if (decode instanceof CommonResponse) { CommonResponse commonResponse = (CommonResponse) decode; if (response.status() == 202) { - log.warn("workflow engine starter rpc async invoke return msg: {}", commonResponse.getMsg()); + log.warn("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg()); } return commonResponse.getData(); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 0a122812b..980ba6d41 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -4,12 +4,15 @@ import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.azxo.framework.common.constatns.Constants; import feign.Client; import feign.RequestInterceptor; +import feign.Retryer; import feign.Target; import feign.codec.Decoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.MDC; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; @@ -26,6 +29,7 @@ import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_H import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; +import static java.util.concurrent.TimeUnit.SECONDS; /** * Starter Feign Client 的自定义的配置 @@ -36,6 +40,11 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_ public class WorkflowEngineStarterFeignConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterFeignConfiguration.class); + @Bean + public Retryer defaultRetryer() { + return new Retryer.Default(100, SECONDS.toMillis(1), 3); + } + @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, @Qualifier("workflowEngineStarterEventProducer") EventProducer eventProducer, @@ -53,12 +62,15 @@ public class WorkflowEngineStarterFeignConfiguration { Environment environment, String serviceVersion) { return template -> { + // 接入应用上报 template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); + // 接口的同步异步模式 RpcInvokeModeEnum rpcInvokeModeEnum = ThreadUtil.get(); if (Objects.isNull(rpcInvokeModeEnum)) { log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); rpcInvokeModeEnum = starterProperties.getInvokeMode(); } + // 通过服务端的校验 template.header(STARTER_INVOKE_MODE, rpcInvokeModeEnum.name()); Target.HardCodedTarget target = (Target.HardCodedTarget) template.feignTarget(); String apiClassPath = target.type().getName(); @@ -66,7 +78,8 @@ public class WorkflowEngineStarterFeignConfiguration { template.header(HEADER_HTTP_CLIENT, HEADER_HTTP_CLIENT_VALUE); template.header(HEADER_API_VERSION, serviceVersion); } - // TODO 还需要添加链路追踪相关信息 + //链路追踪 + template.header(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC)); }; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java new file mode 100644 index 000000000..6e7f100cf --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.listener.filter; + +import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; +import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; + +/** + * MessageNotificationEvent 的自定义过滤接口 + * + * @author wangli + * @since 2024/6/5 15:49 + */ +public interface MessageNotificationEventFilter extends BasicMessageQueueFilter { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java new file mode 100644 index 000000000..141886901 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.listener.filter; + +import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; +import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; + +/** + * ProcessActivityEvent 自定义的过滤接口 + * + * @author wangli + * @since 2024/6/5 15:49 + */ +public interface ProcessActivityEventFilter extends BasicMessageQueueFilter { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java new file mode 100644 index 000000000..fc65dd682 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.listener.filter; + +import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; +import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; + +/** + * ProcessInstanceEvent 自定义的过滤接口 + * + * @author wangli + * @since 2024/6/5 15:44 + */ +public interface ProcessInstanceEventFilter extends BasicMessageQueueFilter { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java new file mode 100644 index 000000000..8298492a6 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.listener.filter; + +import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; +import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; + +/** + * ProcessTaskEvent 自定义的过滤接口 + * + * @author wangli + * @since 2024/6/5 15:50 + */ +public interface ProcessTaskEventFilter extends BasicMessageQueueFilter { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/global/BroadcastMessageQueueFilter.java similarity index 58% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/global/BroadcastMessageQueueFilter.java index 464e57b41..24974e3e8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/BroadcastMessageQueueFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/global/BroadcastMessageQueueFilter.java @@ -1,10 +1,12 @@ -package cn.axzo.workflow.starter.listener; +package cn.axzo.workflow.starter.listener.filter.global; import org.apache.rocketmq.common.message.MessageExt; import org.springframework.core.Ordered; /** - * 业务可扩展的 MQ 消息过滤规则 + * 对流程引擎广播的事件进行全局过滤,业务可扩展的 MQ 消息过滤接口 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer.MIN_VALUE - Integer.MAX_VALUE) * * @author wangli * @since 2024/6/4 17:04 @@ -13,7 +15,7 @@ public interface BroadcastMessageQueueFilter extends Ordered { /** * @param message MQ 消息元数据 - * @param jsonData MQ 消息中的 payload,是 JSON 格式的字符串,自行转成对应对象 + * @param jsonData MQ 消息中的 payload,是 JSON 格式的字符串 * @return */ boolean doFilter(MessageExt message, String jsonData); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index e982c676f..8464ebdf9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -14,28 +15,32 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -public abstract class AbstractWorkflowListener implements WorkflowListener { +public abstract class AbstractWorkflowListener, Target> implements WorkflowListener { private static final Logger log = LoggerFactory.getLogger(AbstractWorkflowListener.class); - protected final List businessListeners; + + protected final List businessListeners; + protected final List businessFilters; private final ListenerExecutor listenerExecutor; - public AbstractWorkflowListener(ListenerExecutor listenerExecutor, ObjectProvider> provider) { + public AbstractWorkflowListener(ListenerExecutor listenerExecutor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { this.listenerExecutor = listenerExecutor; - this.businessListeners = getOrderedBusinessListeners(provider); + this.businessListeners = getOrderedBusinessListeners(handlerProvider); + this.businessFilters = getOrderedBusinessFilters(filterProvider); } - protected final boolean emptyListener() { - if (CollectionUtils.isEmpty(businessListeners)) { - log.info("not {}'s Bean found, will be skip it. please check @Component annotation...", this.getClass().getSimpleName()); - return true; - } - return false; + private List getOrderedBusinessFilters(ObjectProvider> filterProvider) { + return filterProvider.getIfAvailable(Collections::emptyList) + .stream() + .sorted(Comparator.comparingInt(Ordered::getOrder)) + .collect(Collectors.toList()); } - protected List getOrderedBusinessListeners(ObjectProvider> provider) { - return provider.getIfAvailable(Collections::emptyList) + protected List getOrderedBusinessListeners(ObjectProvider> handlerProvider) { + return handlerProvider.getIfAvailable(Collections::emptyList) .stream() .sorted(Comparator.comparingInt(Ordered::getOrder)) .collect(Collectors.toList()); @@ -43,13 +48,24 @@ public abstract class AbstractWorkflowListener implements Wor @Override public void handleEvent(Event event, EventConsumer.Context context) { - if (emptyListener()) { + if (CollectionUtils.isEmpty(businessListeners)) { return; } - onEvent(event, context); + + Target convert = convert(event); + + for (F filter : businessFilters) { + if (filter.doFilter(event, convert)) { + return; + } + } + + onEvent(convert, context); } - protected abstract void onEvent(Event event, EventConsumer.Context context); + protected abstract Target convert(Event event); + + protected abstract void onEvent(Target data, EventConsumer.Context context); protected ListenerExecutor getListenerExecutor() { return listenerExecutor; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 95094aa8a..9f1c19156 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.filter.ProcessActivityEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -20,20 +21,26 @@ import java.util.stream.Collectors; * @author wangli * @since 2024/5/21 15:51 */ -public class InnerActivityEventListener extends AbstractWorkflowListener { +public class InnerActivityEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> Arrays.stream(ProcessActivityEventEnum.values()).map(ProcessActivityEventEnum::getEventCode) .collect(Collectors.toList()); - public InnerActivityEventListener(ListenerExecutor executor, ObjectProvider> provider) { - super(executor, provider); + public InnerActivityEventListener(ListenerExecutor executor, + ObjectProvider> provider, + ObjectProvider> filterProvider) { + super(executor, provider, filterProvider); } @Override - public void onEvent(Event event, EventConsumer.Context context) { - ProcessActivityDTO activityDTO = event.normalizedData(ProcessActivityDTO.class); + protected ProcessActivityDTO convert(Event event) { + return event.normalizedData(ProcessActivityDTO.class); + } + + @Override + public void onEvent(ProcessActivityDTO activityDTO, EventConsumer.Context context) { ProcessActivityEventEnum type = activityDTO.getType(); for (ProcessActivityEventHandler activityListener : businessListeners) { Consumer consumer = null; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index 33fe25e7f..f86521293 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.filter.ProcessInstanceEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -20,20 +21,26 @@ import java.util.stream.Collectors; * @author wangli * @since 2024/5/21 15:51 */ -public class InnerInstanceEventListener extends AbstractWorkflowListener { +public class InnerInstanceEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> Arrays.stream(ProcessInstanceEventEnum.values()).map(ProcessInstanceEventEnum::getEventCode) .collect(Collectors.toList()); - public InnerInstanceEventListener(ListenerExecutor listenerExecutor, ObjectProvider> provider) { - super(listenerExecutor, provider); + public InnerInstanceEventListener(ListenerExecutor listenerExecutor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { + super(listenerExecutor, handlerProvider, filterProvider); } @Override - public void onEvent(Event event, EventConsumer.Context context) { - ProcessInstanceDTO instanceDTO = event.normalizedData(ProcessInstanceDTO.class); + protected ProcessInstanceDTO convert(Event event) { + return event.normalizedData(ProcessInstanceDTO.class); + } + + @Override + public void onEvent(ProcessInstanceDTO instanceDTO, EventConsumer.Context context) { ProcessInstanceEventEnum type = instanceDTO.getType(); for (ProcessInstanceEventHandler instanceListener : businessListeners) { Consumer consumer = null; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java index a7ab9dabe..34a74f830 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.filter.MessageNotificationEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -20,20 +21,24 @@ import java.util.stream.Collectors; * @author wangli * @since 2024/5/21 15:53 */ -public class InnerNotificationEventListener extends AbstractWorkflowListener { +public class InnerNotificationEventListener extends AbstractWorkflowListener { private final static Logger log = LoggerFactory.getLogger(InnerNotificationEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> Arrays.stream(ProcessMessagePushEventEnum.values()).map(ProcessMessagePushEventEnum::getEventCode) .collect(Collectors.toList()); - public InnerNotificationEventListener(ListenerExecutor executor, ObjectProvider> provider) { - super(executor, provider); + public InnerNotificationEventListener(ListenerExecutor executor, ObjectProvider> provider, ObjectProvider> filterProvider) { + super(executor, provider, filterProvider); } @Override - public void onEvent(Event event, EventConsumer.Context context) { - MessagePushDTO instanceDTO = event.normalizedData(MessagePushDTO.class); + protected MessagePushDTO convert(Event event) { + return event.normalizedData(MessagePushDTO.class); + } + + @Override + public void onEvent(MessagePushDTO instanceDTO, EventConsumer.Context context) { ProcessMessagePushEventEnum type = instanceDTO.getType(); for (MessageNotificationEventHandler noticeListener : businessListeners) { Consumer consumer = null; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 616721d21..05be37555 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.listener.filter.ProcessTaskEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -20,20 +21,24 @@ import java.util.stream.Collectors; * @author wangli * @since 2024/5/21 15:51 */ -public class InnerTaskEventListener extends AbstractWorkflowListener { +public class InnerTaskEventListener extends AbstractWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerTaskEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> Arrays.stream(ProcessTaskEventEnum.values()).map(ProcessTaskEventEnum::getEventCode) .collect(Collectors.toList()); - public InnerTaskEventListener(ListenerExecutor executor, ObjectProvider> provider) { - super(executor, provider); + public InnerTaskEventListener(ListenerExecutor executor, ObjectProvider> provider, ObjectProvider> filterProvider) { + super(executor, provider, filterProvider); } @Override - public void onEvent(Event event, EventConsumer.Context context) { - ProcessTaskDTO taskDTO = event.normalizedData(ProcessTaskDTO.class); + protected ProcessTaskDTO convert(Event event) { + return event.normalizedData(ProcessTaskDTO.class); + } + + @Override + public void onEvent(ProcessTaskDTO taskDTO, EventConsumer.Context context) { ProcessTaskEventEnum type = taskDTO.getType(); for (ProcessTaskEventHandler taskListener : businessListeners) { Consumer consumer = null; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java new file mode 100644 index 000000000..8e7f60bf7 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java @@ -0,0 +1,24 @@ +package cn.axzo.workflow.starter.mq.broadcast.filter; + +import cn.axzo.framework.rocketmq.Event; +import org.springframework.core.Ordered; + +/** + * 一个基于某个具体的 MQ 消息的过滤接口 + * + * @author wangli + * @since 2024/6/5 16:08 + */ +public interface BasicMessageQueueFilter extends Ordered { + + /** + * 基于具体的 {@link Event.EventCode#module} 下的自定义的 MQ 过滤器 + * + * @param event 事件原对象 + * @param data payload 被转换后的目标对象 + * @return + */ + default boolean doFilter(Event event, T data) { + return false; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java index eb4146d46..7b34a14fe 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java @@ -1,12 +1,14 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; -import cn.axzo.workflow.starter.listener.BroadcastMessageQueueFilter; +import cn.axzo.workflow.starter.listener.filter.global.BroadcastMessageQueueFilter; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.core.Ordered; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -43,6 +45,27 @@ public class InnerFilterExtension implements InnerMessageQueueHandleBeforeFilter } } return false; + + +// for (BroadcastMessageQueueFilter businessFilter : businessFilters) { +// Object payload = new String(message.getBody(), UTF_8); +// Class typeClass = getParameterizedTypeClass(businessFilter); +// if(Objects.nonNull(typeClass)) { +// payload = JSON.parseObject((String) payload, typeClass); +// } +// if (businessFilter.doFilter(message, payload)) { +// return true; +// } +// } + } + + + private Class getParameterizedTypeClass(BroadcastMessageQueueFilter filter) { + Type type = filter.getClass().getGenericInterfaces()[0]; + if (type instanceof ParameterizedType) { + return (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; + } + return null; } } From 903bf6b7a29dae00b721ca88fcba0a5997af38e2 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Jun 2024 17:37:39 +0800 Subject: [PATCH 072/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20RocketMQ=20=E6=B6=88=E8=B4=B9=E8=80=85=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E5=92=8C=E5=AE=9E=E4=BE=8B=E5=8C=96=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...lowEngineStarterRocketMQConfiguration.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java index 02f46130e..76fb047bb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java @@ -27,6 +27,7 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -37,7 +38,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; @@ -96,7 +96,7 @@ public class WorkflowEngineStarterRocketMQConfiguration { consumeMode = ConsumeMode.ORDERLY, nameServer = "${rocketmq.name-server}" ) - public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener { + public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); @Resource(name = "eventConsumer") @@ -109,14 +109,6 @@ public class WorkflowEngineStarterRocketMQConfiguration { private ObjectProvider> businessFilterProvider; private List filters; - @PostConstruct - public void init() { - this.filters = ImmutableList.of( - new InnerFilterMQOwnerShipInner(starterProperties, applicationName), - new InnerFilterDefinitionKeyInner(starterProperties), - new InnerFilterExtension(businessFilterProvider)); - } - @Override public void onMessage(MessageExt message) { for (InnerMessageQueueHandleBeforeFilter filter : filters) { @@ -127,6 +119,14 @@ public class WorkflowEngineStarterRocketMQConfiguration { } super.onEvent(message, eventConsumer); } + + @Override + public void afterPropertiesSet() { + this.filters = ImmutableList.of( + new InnerFilterMQOwnerShipInner(starterProperties, applicationName), + new InnerFilterDefinitionKeyInner(starterProperties), + new InnerFilterExtension(businessFilterProvider)); + } } @Bean @@ -243,8 +243,8 @@ public class WorkflowEngineStarterRocketMQConfiguration { replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) - public static class WorkflowEngineClientRetryConsumer extends BaseListener implements RocketMQListener { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineClientRetryConsumer.class); + public static class WorkflowEngineStarterRetryConsumer extends BaseListener implements RocketMQListener, InitializingBean { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryConsumer.class); @Resource(name = "workflowEngineStarterEventConsumer") private EventConsumer workflowEngineStarterEventConsumer; @@ -254,11 +254,6 @@ public class WorkflowEngineStarterRocketMQConfiguration { private WorkflowEngineStarterProperties starterProperties; private InnerMessageQueueHandleBeforeFilter filter; - @PostConstruct - public void init() { - this.filter = new InnerFilterMQOwnerShipInner(starterProperties, applicationName); - } - @Override public void onMessage(MessageExt message) { if (filter.doFilter(message)) { @@ -267,6 +262,11 @@ public class WorkflowEngineStarterRocketMQConfiguration { } super.onEvent(message, workflowEngineStarterEventConsumer); } + + @Override + public void afterPropertiesSet() { + this.filter = new InnerFilterMQOwnerShipInner(starterProperties, applicationName); + } } @Bean From dc768f785cbae488f439738fb82e42831237041b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Jun 2024 17:48:56 +0800 Subject: [PATCH 073/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E7=B1=BB=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 33 ++--- ...EngineStarterBroadcastMQConfiguration.java | 127 ++++++++++++++++++ ...ngineStarterRPCInvokeMQConfiguration.java} | 92 +------------ .../MessageNotificationEventHandler.java | 2 +- .../ProcessActivityEventHandler.java | 2 +- .../ProcessInstanceEventHandler.java | 2 +- .../ProcessTaskEventHandler.java | 2 +- .../execute/ListenerExecutor.java | 4 +- .../AbstractListenerInterceptor.java | 2 +- .../interceptor/ExecuteInterceptor.java | 4 +- .../execute/interceptor/ExecutorInvoker.java | 4 +- .../interceptor/FailBackInterceptor.java | 4 +- .../interceptor/FailFastInterceptor.java | 4 +- .../interceptor/FailOverInterceptor.java | 4 +- .../execute/interceptor/LogInterceptor.java | 4 +- .../MessageNotificationEventFilter.java | 2 +- .../filter/ProcessActivityEventFilter.java | 2 +- .../filter/ProcessInstanceEventFilter.java | 2 +- .../filter/ProcessTaskEventFilter.java | 2 +- .../global/BroadcastMessageQueueFilter.java | 2 +- .../consumer/AbstractWorkflowListener.java | 2 +- .../consumer/InnerActivityEventListener.java | 6 +- .../consumer/InnerInstanceEventListener.java | 6 +- .../InnerNotificationEventListener.java | 6 +- .../consumer/InnerTaskEventListener.java | 6 +- .../filter/InnerFilterExtension.java | 2 +- 26 files changed, 188 insertions(+), 140 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{WorkflowEngineStarterRocketMQConfiguration.java => WorkflowEngineStarterRPCInvokeMQConfiguration.java} (67%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/MessageNotificationEventHandler.java (96%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/ProcessActivityEventHandler.java (95%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/ProcessInstanceEventHandler.java (97%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/ProcessTaskEventHandler.java (95%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/ListenerExecutor.java (86%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/AbstractListenerInterceptor.java (82%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/ExecuteInterceptor.java (64%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/ExecutorInvoker.java (79%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/FailBackInterceptor.java (81%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/FailFastInterceptor.java (85%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/FailOverInterceptor.java (93%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/execute/interceptor/LogInterceptor.java (86%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/filter/MessageNotificationEventFilter.java (87%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/filter/ProcessActivityEventFilter.java (87%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/filter/ProcessInstanceEventFilter.java (87%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/filter/ProcessTaskEventFilter.java (87%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{listener => handler}/filter/global/BroadcastMessageQueueFilter.java (91%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 8f64dddf2..8ad4b37dd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -2,21 +2,21 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; -import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; -import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; -import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; -import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; -import cn.axzo.workflow.starter.listener.execute.interceptor.ExecuteInterceptor; -import cn.axzo.workflow.starter.listener.execute.interceptor.ExecutorInvoker; -import cn.axzo.workflow.starter.listener.execute.interceptor.FailBackInterceptor; -import cn.axzo.workflow.starter.listener.execute.interceptor.FailFastInterceptor; -import cn.axzo.workflow.starter.listener.execute.interceptor.FailOverInterceptor; -import cn.axzo.workflow.starter.listener.execute.interceptor.LogInterceptor; -import cn.axzo.workflow.starter.listener.filter.MessageNotificationEventFilter; -import cn.axzo.workflow.starter.listener.filter.ProcessActivityEventFilter; -import cn.axzo.workflow.starter.listener.filter.ProcessInstanceEventFilter; -import cn.axzo.workflow.starter.listener.filter.ProcessTaskEventFilter; +import cn.axzo.workflow.starter.handler.MessageNotificationEventHandler; +import cn.axzo.workflow.starter.handler.ProcessActivityEventHandler; +import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler; +import cn.axzo.workflow.starter.handler.ProcessTaskEventHandler; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.interceptor.ExecuteInterceptor; +import cn.axzo.workflow.starter.handler.execute.interceptor.ExecutorInvoker; +import cn.axzo.workflow.starter.handler.execute.interceptor.FailBackInterceptor; +import cn.axzo.workflow.starter.handler.execute.interceptor.FailFastInterceptor; +import cn.axzo.workflow.starter.handler.execute.interceptor.FailOverInterceptor; +import cn.axzo.workflow.starter.handler.execute.interceptor.LogInterceptor; +import cn.axzo.workflow.starter.handler.filter.MessageNotificationEventFilter; +import cn.axzo.workflow.starter.handler.filter.ProcessActivityEventFilter; +import cn.axzo.workflow.starter.handler.filter.ProcessInstanceEventFilter; +import cn.axzo.workflow.starter.handler.filter.ProcessTaskEventFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; @@ -43,7 +43,7 @@ import java.util.List; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) @EnableFeignClients(clients = {WorkflowCoreService.class}) -@Import(WorkflowEngineStarterRocketMQConfiguration.class) +@Import({WorkflowEngineStarterBroadcastMQConfiguration.class, WorkflowEngineStarterRPCInvokeMQConfiguration.class}) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); @@ -54,6 +54,7 @@ public class WorkflowEngineStarterAutoConfiguration { List interceptors = new ArrayList<>(); interceptors.add(new LogInterceptor()); interceptors.add(getFailInterceptor(starterProperties)); + // TODO // if (!CollectionUtils.isEmpty(additionalInterceptors)) { // additionalInterceptors.forEach(interceptor -> interceptor.setNext(interceptor)); // } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java new file mode 100644 index 000000000..cfd1f7960 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java @@ -0,0 +1,127 @@ +package cn.axzo.workflow.starter; + +import cn.axzo.framework.rocketmq.BaseListener; +import cn.axzo.framework.rocketmq.DefaultEventConsumer; +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.framework.rocketmq.EventHandlerRepository; +import cn.axzo.framework.rocketmq.EventProducer; +import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; +import cn.axzo.workflow.starter.handler.filter.global.BroadcastMessageQueueFilter; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKeyInner; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShipInner; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; +import com.google.common.collect.ImmutableList; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.spring.annotation.ConsumeMode; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +import static cn.axzo.workflow.starter.WorkflowEngineStarterRPCInvokeMQConfiguration.DEFAULT_EVENT; + +/** + * 配置监听流程引擎服务广播消息的 RocketMQ 相关配置 + * + * @author wangli + * @since 2024/6/5 17:39 + */ +@Configuration(proxyBeanMethods = false) +public class WorkflowEngineStarterBroadcastMQConfiguration { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterBroadcastMQConfiguration.class); + + @Value("${spring.application.name}") + private String applicationName; + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + //================================= Workflow Engine Broadcast MQ =================================// + @Bean + @ConditionalOnMissingBean(EventHandlerRepository.class) + public EventHandlerRepository eventHandlerRepository() { + return new EventHandlerRepository((ex, logText) -> { + log.warn("MQ, handle warning {}", logText, ex); + if (Objects.nonNull(ex)) { + throw new RuntimeException(ex); + } + }); + } + + @Bean + @ConditionalOnMissingBean(EventProducer.class) + public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { + Consumer callback = eventWrapper -> { + if (eventWrapper.isHandled()) { + // 只收集被App真正消费的消息. + Event event = eventWrapper.getEvent(); + log.info("WorkflowEngine Broadcast MQ, handled event: {}", event.toPrettyJsonString()); + } + }; + return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); + } + + @Component + @Conditional(NonContainerEnvironmentCondition.class) + @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", + consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", + consumeMode = ConsumeMode.ORDERLY, + nameServer = "${rocketmq.name-server}" + ) + public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); + + @Resource(name = "eventConsumer") + private EventConsumer eventConsumer; + @Value("${spring.application.name}") + private String applicationName; + @Resource + private WorkflowEngineStarterProperties starterProperties; + @Resource + private ObjectProvider> businessFilterProvider; + private List filters; + + @Override + public void onMessage(MessageExt message) { + for (InnerMessageQueueHandleBeforeFilter filter : filters) { + if (filter.doFilter(message)) { + log.info("message has been filtered"); + return; + } + } + super.onEvent(message, eventConsumer); + } + + @Override + public void afterPropertiesSet() { + this.filters = ImmutableList.of( + new InnerFilterMQOwnerShipInner(starterProperties, applicationName), + new InnerFilterDefinitionKeyInner(starterProperties), + new InnerFilterExtension(businessFilterProvider)); + } + } + + @Bean + public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, + WorkflowEngineStarterProperties workflowEngineStarterProperties, + List listenerProvider) { + return new WorkflowEngineBroadcastEventListener(eventConsumer, workflowEngineStarterProperties, listenerProvider); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRPCInvokeMQConfiguration.java similarity index 67% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRPCInvokeMQConfiguration.java index 76fb047bb..cdd5efc1d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRocketMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRPCInvokeMQConfiguration.java @@ -10,16 +10,10 @@ import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; -import cn.axzo.workflow.starter.listener.filter.global.BroadcastMessageQueueFilter; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKeyInner; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShipInner; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; -import com.google.common.collect.ImmutableList; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; @@ -28,7 +22,6 @@ import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -40,7 +33,6 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.HashMap; -import java.util.List; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -48,95 +40,23 @@ import java.util.function.Consumer; import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; /** - * 配置 RocketMQ 事件监听器 + * 配置 RPC 动作的 RocketMQ 消息的发送方和消息方等配置信息 * * @author wangli * @since 2024/5/30 14:05 */ @Configuration(proxyBeanMethods = false) -public class WorkflowEngineStarterRocketMQConfiguration { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRocketMQConfiguration.class); +public class WorkflowEngineStarterRPCInvokeMQConfiguration { + private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRPCInvokeMQConfiguration.class); + + public static final String DEFAULT_MODULE = "workflowEngine"; + public static final String DEFAULT_EVENT = "topic_workflow_engine_"; - private static final String DEFAULT_MODULE = "workflowEngine"; - private static final String DEFAULT_EVENT = "topic_workflow_engine_"; @Value("${spring.application.name}") private String applicationName; @Value("${spring.profiles.active:dev}") private String activeProfile; - //================================= Workflow Engine Broadcast MQ =================================// - @Bean - @ConditionalOnMissingBean(EventHandlerRepository.class) - public EventHandlerRepository eventHandlerRepository() { - return new EventHandlerRepository((ex, logText) -> { - log.warn("MQ, handle warning {}", logText, ex); - if (Objects.nonNull(ex)) { - throw new RuntimeException(ex); - } - }); - } - - @Bean - @ConditionalOnMissingBean(EventProducer.class) - public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { - Consumer callback = eventWrapper -> { - if (eventWrapper.isHandled()) { - // 只收集被App真正消费的消息. - Event event = eventWrapper.getEvent(); - log.info("WorkflowEngine Broadcast MQ, handled event: {}", event.toPrettyJsonString()); - } - }; - return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); - } - - @Component - @Conditional(NonContainerEnvironmentCondition.class) - @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", - consumeMode = ConsumeMode.ORDERLY, - nameServer = "${rocketmq.name-server}" - ) - public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); - - @Resource(name = "eventConsumer") - private EventConsumer eventConsumer; - @Value("${spring.application.name}") - private String applicationName; - @Resource - private WorkflowEngineStarterProperties starterProperties; - @Resource - private ObjectProvider> businessFilterProvider; - private List filters; - - @Override - public void onMessage(MessageExt message) { - for (InnerMessageQueueHandleBeforeFilter filter : filters) { - if (filter.doFilter(message)) { - log.info("message has been filtered"); - return; - } - } - super.onEvent(message, eventConsumer); - } - - @Override - public void afterPropertiesSet() { - this.filters = ImmutableList.of( - new InnerFilterMQOwnerShipInner(starterProperties, applicationName), - new InnerFilterDefinitionKeyInner(starterProperties), - new InnerFilterExtension(businessFilterProvider)); - } - } - - @Bean - public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, - WorkflowEngineStarterProperties workflowEngineStarterProperties, - List listenerProvider) { - return new WorkflowEngineBroadcastEventListener(eventConsumer, workflowEngineStarterProperties, listenerProvider); - } - - //======================================= RPC Invoke MQ ========================================// /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java similarity index 96% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationEventHandler.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java index 03ffa611d..3fc18b031 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/MessageNotificationEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener; +package cn.axzo.workflow.starter.handler; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import org.springframework.core.Ordered; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java similarity index 95% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityEventHandler.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java index 5769d4437..53b1262f2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessActivityEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener; +package cn.axzo.workflow.starter.handler; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import org.springframework.core.Ordered; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java similarity index 97% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceEventHandler.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java index b969dac49..5aadd8b63 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessInstanceEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener; +package cn.axzo.workflow.starter.handler; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java similarity index 95% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskEventHandler.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java index 8aa906478..033e4c2e8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/ProcessTaskEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener; +package cn.axzo.workflow.starter.handler; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import org.springframework.core.Ordered; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/ListenerExecutor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java similarity index 86% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/ListenerExecutor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java index 3f184742e..fed2de014 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/ListenerExecutor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java @@ -1,7 +1,7 @@ -package cn.axzo.workflow.starter.listener.execute; +package cn.axzo.workflow.starter.handler.execute; import cn.axzo.framework.domain.ServiceException; -import cn.axzo.workflow.starter.listener.execute.interceptor.ExecuteInterceptor; +import cn.axzo.workflow.starter.handler.execute.interceptor.ExecuteInterceptor; import java.util.List; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/AbstractListenerInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/AbstractListenerInterceptor.java similarity index 82% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/AbstractListenerInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/AbstractListenerInterceptor.java index 0679bee62..8fbec537c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/AbstractListenerInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/AbstractListenerInterceptor.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; public abstract class AbstractListenerInterceptor implements ExecuteInterceptor { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecuteInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java similarity index 64% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecuteInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java index de6290d70..fd63c037d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecuteInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecutorInvoker.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java similarity index 79% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecutorInvoker.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java index eb90f956d..838932627 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/ExecutorInvoker.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailBackInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java similarity index 81% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailBackInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java index ff84e3873..b446fd0ba 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailBackInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailFastInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java similarity index 85% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailFastInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java index 544059200..2cd6d0ef4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailFastInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java @@ -1,7 +1,7 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; import cn.axzo.workflow.starter.common.exception.WorkflowListenerExeException; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java similarity index 93% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailOverInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index ff525cba4..aeaf8296d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java similarity index 86% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/LogInterceptor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java index 17acfaf74..58f82de6b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java @@ -1,6 +1,6 @@ -package cn.axzo.workflow.starter.listener.execute.interceptor; +package cn.axzo.workflow.starter.handler.execute.interceptor; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StopWatch; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java similarity index 87% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java index 6e7f100cf..d7de82061 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/MessageNotificationEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener.filter; +package cn.axzo.workflow.starter.handler.filter; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java similarity index 87% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java index 141886901..a79f2b539 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessActivityEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener.filter; +package cn.axzo.workflow.starter.handler.filter; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java similarity index 87% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java index fc65dd682..91ab141d7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessInstanceEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener.filter; +package cn.axzo.workflow.starter.handler.filter; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java similarity index 87% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java index 8298492a6..afd16f414 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/ProcessTaskEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener.filter; +package cn.axzo.workflow.starter.handler.filter; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/global/BroadcastMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java similarity index 91% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/global/BroadcastMessageQueueFilter.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java index 24974e3e8..f3426179f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/listener/filter/global/BroadcastMessageQueueFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.listener.filter.global; +package cn.axzo.workflow.starter.handler.filter.global; import org.apache.rocketmq.common.message.MessageExt; import org.springframework.core.Ordered; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index 8464ebdf9..7b39ab3ea 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -2,7 +2,7 @@ package cn.axzo.workflow.starter.mq.broadcast.consumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java index 9f1c19156..897a2430e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerActivityEventListener.java @@ -4,9 +4,9 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessActivityEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessActivityDTO; -import cn.axzo.workflow.starter.listener.ProcessActivityEventHandler; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; -import cn.axzo.workflow.starter.listener.filter.ProcessActivityEventFilter; +import cn.axzo.workflow.starter.handler.ProcessActivityEventHandler; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.filter.ProcessActivityEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java index f86521293..a5bdd17ae 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerInstanceEventListener.java @@ -4,9 +4,9 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO; -import cn.axzo.workflow.starter.listener.ProcessInstanceEventHandler; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; -import cn.axzo.workflow.starter.listener.filter.ProcessInstanceEventFilter; +import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.filter.ProcessInstanceEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java index 34a74f830..e4ba46226 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerNotificationEventListener.java @@ -4,9 +4,9 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum; import cn.axzo.workflow.common.model.response.mq.MessagePushDTO; -import cn.axzo.workflow.starter.listener.MessageNotificationEventHandler; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; -import cn.axzo.workflow.starter.listener.filter.MessageNotificationEventFilter; +import cn.axzo.workflow.starter.handler.MessageNotificationEventHandler; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.filter.MessageNotificationEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java index 05be37555..f6f9b62cd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/InnerTaskEventListener.java @@ -4,9 +4,9 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; -import cn.axzo.workflow.starter.listener.ProcessTaskEventHandler; -import cn.axzo.workflow.starter.listener.execute.ListenerExecutor; -import cn.axzo.workflow.starter.listener.filter.ProcessTaskEventFilter; +import cn.axzo.workflow.starter.handler.ProcessTaskEventHandler; +import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import cn.axzo.workflow.starter.handler.filter.ProcessTaskEventFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java index 7b34a14fe..2056ae6dc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; -import cn.axzo.workflow.starter.listener.filter.global.BroadcastMessageQueueFilter; +import cn.axzo.workflow.starter.handler.filter.global.BroadcastMessageQueueFilter; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From be09801a4dbad1bb706bf6afa682f7cdb7df0ce7 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Jun 2024 18:23:22 +0800 Subject: [PATCH 074/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20RocketMQ=20=E7=9A=84=20tool=20=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 5 +++++ ...orkflowEngineStarterAutoConfiguration.java | 22 +++++++++++++++++++ .../starter/mq/monitor/DefaultMQMonitor.java | 10 +++++++++ 3 files changed, 37 insertions(+) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index 28a852e99..93f82f89f 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -28,5 +28,10 @@ axzo-common-rocketmq provided + + org.apache.rocketmq + rocketmq-tools + 4.9.1 + diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 8ad4b37dd..9f511b868 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -22,6 +22,11 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; @@ -107,4 +112,21 @@ public class WorkflowEngineStarterAutoConfiguration { } } + @Bean(destroyMethod = "shutdown", name = "defaultMQAdminExt") + public DefaultMQAdminExt defaultMQAdminExt() { + String namesrvAddress = System.getProperty("rocketmq.name-server"); + if (StringUtils.isBlank(namesrvAddress)) { + log.error("Build DefaultMQAdminExt error, namesrv is null"); + throw new RuntimeException("Build DefaultMQAdminExt error, namesrv is null", null); + } + DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt((RPCHook) null, 5000L); + defaultMQAdminExt.setInstanceName("admin-" + System.currentTimeMillis()); + defaultMQAdminExt.setNamesrvAddr(namesrvAddress); + try { + defaultMQAdminExt.start(); + } catch (MQClientException ex) { + log.error(String.format("init default admin error, namesrv=%s", System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY)), ex); + } + return defaultMQAdminExt; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java new file mode 100644 index 000000000..c4993f702 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.starter.mq.monitor; + +/** + * TODO + * + * @author wangli + * @since 2024/6/5 17:49 + */ +public class DefaultMQMonitor { +} From 46e0bced8054a14ad959f85f21a02b813c9be13c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Jun 2024 20:41:11 +0800 Subject: [PATCH 075/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E8=B0=83=E6=95=B4=20MQ=20=E9=9B=86=E7=BE=A4=E4=B8=8E?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E7=9A=84=E6=B6=88=E8=B4=B9=E5=B7=AE=E5=BC=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...a => StarterBroadcastMQConfiguration.java} | 6 +-- ...a => StarterRPCInvokeMQConfiguration.java} | 4 +- ...orkflowEngineStarterAutoConfiguration.java | 8 +++- .../NonContainerEnvironmentCondition.java | 44 ++++--------------- .../common/constant/StarterConstants.java | 1 + .../starter/mq/monitor/DefaultMQMonitor.java | 30 +++++++++++++ 6 files changed, 51 insertions(+), 42 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{WorkflowEngineStarterBroadcastMQConfiguration.java => StarterBroadcastMQConfiguration.java} (95%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{WorkflowEngineStarterRPCInvokeMQConfiguration.java => StarterRPCInvokeMQConfiguration.java} (98%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java similarity index 95% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index cfd1f7960..291cddd3c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -36,7 +36,7 @@ import java.util.List; import java.util.Objects; import java.util.function.Consumer; -import static cn.axzo.workflow.starter.WorkflowEngineStarterRPCInvokeMQConfiguration.DEFAULT_EVENT; +import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; /** * 配置监听流程引擎服务广播消息的 RocketMQ 相关配置 @@ -45,8 +45,8 @@ import static cn.axzo.workflow.starter.WorkflowEngineStarterRPCInvokeMQConfigura * @since 2024/6/5 17:39 */ @Configuration(proxyBeanMethods = false) -public class WorkflowEngineStarterBroadcastMQConfiguration { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterBroadcastMQConfiguration.class); +public class StarterBroadcastMQConfiguration { + private final Logger log = LoggerFactory.getLogger(StarterBroadcastMQConfiguration.class); @Value("${spring.application.name}") private String applicationName; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java similarity index 98% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRPCInvokeMQConfiguration.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index cdd5efc1d..ac1a73a9f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -46,8 +46,8 @@ import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; * @since 2024/5/30 14:05 */ @Configuration(proxyBeanMethods = false) -public class WorkflowEngineStarterRPCInvokeMQConfiguration { - private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRPCInvokeMQConfiguration.class); +public class StarterRPCInvokeMQConfiguration { + private final Logger log = LoggerFactory.getLogger(StarterRPCInvokeMQConfiguration.class); public static final String DEFAULT_MODULE = "workflowEngine"; public static final String DEFAULT_EVENT = "topic_workflow_engine_"; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 9f511b868..360889667 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -22,6 +22,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; +import cn.axzo.workflow.starter.mq.monitor.DefaultMQMonitor; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; @@ -48,7 +49,7 @@ import java.util.List; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) @EnableFeignClients(clients = {WorkflowCoreService.class}) -@Import({WorkflowEngineStarterBroadcastMQConfiguration.class, WorkflowEngineStarterRPCInvokeMQConfiguration.class}) +@Import({StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class}) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); @@ -129,4 +130,9 @@ public class WorkflowEngineStarterAutoConfiguration { } return defaultMQAdminExt; } + + @Bean + public DefaultMQMonitor defaultMQMonitor() { + return new DefaultMQMonitor(); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java index 15d1cdfcc..495c585b0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java @@ -14,13 +14,13 @@ import java.util.Objects; import static cn.axzo.workflow.starter.common.constant.StarterConstants.DEBUGGING_MQ_SUFFIX; import static cn.axzo.workflow.starter.common.constant.StarterConstants.K8S_POD_NAME_SPACE; import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.starter.common.constant.StarterConstants.NACOS_PROFILES_ACTIVE; /** * 用于处理 MQ 的消费者, 在本地启动或在容器中启动时, 能自主控制是否并入统一的消费组 *

* 可查看 {@link WorkflowEngineStarterProperties#joinContainerGroup} 属性, 来了解本类的用途, - * 特别需要注意的是: Starter 是结合 K8S 的命名空间(namespace) 来处理的. 如果公司在变更环境后, - * 可能会导致 {@link NonContainerEnvironmentCondition#mappingNamespace(String)} 方法异常. + * 特别需要注意的是: Starter 是结合 K8S 的命名空间(namespace) 来处理的. * * @author wangli * @since 2024/5/30 22:19 @@ -33,14 +33,16 @@ public class NonContainerEnvironmentCondition implements Condition { public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment(); String myPodNamespace = environment.getProperty(K8S_POD_NAME_SPACE); - + String activeProfile = environment.getProperty(NACOS_PROFILES_ACTIVE); + if (!StringUtils.hasText(activeProfile)) { + activeProfile = environment.getProperty("spring.profiles.active", String.class); + } // 在容器环境时, 强制加入集群消费组 if (StringUtils.hasText(myPodNamespace)) { - environment.getSystemProperties().put(MQ_GID_NAME_SEGMENT, mappingNamespace(myPodNamespace)); + environment.getSystemProperties().put(MQ_GID_NAME_SEGMENT, activeProfile); return true; } - // 优先外部化配置 Boolean joinContainerGroup = environment.getProperty("workflow.engine.starter.join-container-group", Boolean.class); if (Objects.isNull(joinContainerGroup)) { @@ -49,40 +51,10 @@ public class NonContainerEnvironmentCondition implements Condition { } log.debug("workflow engine starter join-container-group status: {} ", joinContainerGroup); - String activeProfile = environment.getProperty("spring.profiles.active", String.class); environment.getSystemProperties().put(MQ_GID_NAME_SEGMENT, - joinContainerGroup ? mappingNamespace(activeProfile) : activeProfile + DEBUGGING_MQ_SUFFIX); + joinContainerGroup ? activeProfile : activeProfile + DEBUGGING_MQ_SUFFIX); return true; } - /** - * 将 K8S 集群的 NameSpace 空间名映射为开发常用的 profile 名称 - * - * @param namespace - * @return - */ - private String mappingNamespace(String namespace) { - if (!StringUtils.hasText(namespace)) { - throw new IllegalArgumentException("namespace is empty"); - } - switch (namespace) { - case "local": - return "local"; - case "dev": - case "java-dev": - return "dev"; - case "test": - return "test"; - case "pre": - return "pre"; - case "live": - return "live"; - case "master": - case "pro": - return "master"; - default: - throw new IllegalArgumentException(String.format("namespace %s is not supported", namespace)); - } - } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java index b74c66ddb..3adb0d1eb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java @@ -10,5 +10,6 @@ public interface StarterConstants { String STARTER_INVOKE_MODE = "WORKFLOW-ENGINE-STARTER-INVOKE-MODE"; String DEBUGGING_MQ_SUFFIX = "_debugging"; String K8S_POD_NAME_SPACE = "MY_POD_NAMESPACE"; + String NACOS_PROFILES_ACTIVE = "NACOS_PROFILES_ACTIVE"; String MQ_GID_NAME_SEGMENT = "GID_SEGMENT"; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java index c4993f702..11fe1704a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java @@ -1,10 +1,40 @@ package cn.axzo.workflow.starter.mq.monitor; +import cn.azxo.framework.common.model.CommonResponse; +import lombok.SneakyThrows; +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + /** * TODO * * @author wangli * @since 2024/6/5 17:49 */ +@RestController +@RequestMapping("/web/workflow/engine/starter/monitor") public class DefaultMQMonitor { + + @Resource + private DefaultMQAdminExt defaultMQAdminExt; + + @SneakyThrows + @GetMapping("/test") + public CommonResponse monitor() { + Map result = new HashMap<>(); + result.put("examineTopicStats", defaultMQAdminExt.examineTopicStats("topic_workflow_engine_dev")); + result.put("gid_senna", defaultMQAdminExt.examineConsumeStats("GID_senna_workflow_engine_debugging_consumer")); + result.put("gid_senna_starter", defaultMQAdminExt.examineConsumeStats("GID_senna_workflow_engine_starter_debugging_consumer")); + result.put("brokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); + result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList("topic_workflow_engine_dev")); + result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo("topic_workflow_engine_dev")); + defaultMQAdminExt.examineTopicConfig(System.getProperty("rocketmq.name-server"), "topic_workflow_engine_dev"); + return CommonResponse.success(result); + } } From 16d20c948f4fde8a6880cf25bcc0b8c91f1a7a24 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Jun 2024 09:39:11 +0800 Subject: [PATCH 076/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=90=88?= =?UTF-8?q?=E5=B9=B6=20master=20=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/client/feign/manage/ProcessCategoryApi.java | 3 +-- .../java/cn/axzo/workflow/common/constant/BpmnConstants.java | 4 ---- .../axzo/workflow/core/mq/CustomRocketMQEventProducer.java | 5 +---- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index d8797e070..0daf1062f 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -1,7 +1,6 @@ package cn.axzo.workflow.client.feign.manage; import cn.axzo.workflow.client.config.CommonFeignConfiguration; -import cn.axzo.workflow.generate.annotition.Management; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; @@ -10,6 +9,7 @@ import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; import cn.axzo.workflow.common.model.response.category.CategoryItemVO; +import cn.axzo.workflow.generate.annotition.Management; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; @@ -34,7 +34,6 @@ import java.util.List; @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) @Management -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}") public interface ProcessCategoryApi { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 0c492d670..ffdd11d80 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -151,10 +151,6 @@ public interface BpmnConstants { * 批量操作配置默认值 */ Boolean SUPPORT_BATCH_OPERATION_DEFAULT_VALUE = false; - /** - * 用于 MQ 的 Header, 记录当前事件的归属应用 - */ - String MQ_OWNERSHIP_APP = "MQ_OWNERSHIP_APPLICATION"; /** * 用于 MQ 的 Header, 记录当前事件的归属应用 */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java index be5113e1e..b0235be43 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/mq/CustomRocketMQEventProducer.java @@ -17,8 +17,6 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; -import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP; - import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION; /** @@ -71,9 +69,8 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer { newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId()); newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId()); // FIXME -// newHeaders.put(MQ_OWNERSHIP_APP, applicationName); +// newHeaders.put(MQ_OWNERSHIP_APPLICATION, applicationName); newHeaders.put(MQ_OWNERSHIP_APPLICATION, "senna"); - newHeaders.put(MQ_OWNERSHIP_APP, applicationName); final Context copiedContext = context.toBuilder().headers(newHeaders).build(); Runnable runnable = () -> { From 6bf6c7f56d94299b8c1997f8bcff672cfc035b8e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Jun 2024 09:47:38 +0800 Subject: [PATCH 077/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E7=89=88=E6=9C=AC=E5=8F=B7=E4=B8=BA=201.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 +++--- workflow-engine-api/pom.xml | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index a9f1a2ab8..84449fd88 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ workflow-engine - 1.3.3-SNAPSHOT + 1.4.0-SNAPSHOT 2.0.0-SNAPSHOT 2.0.0-SNAPSHOT 11.8 @@ -67,7 +67,7 @@ ${project.groupId} workflow-auto-gen - ${project.version} + 1.3.3-SNAPSHOT ${project.groupId} @@ -133,7 +133,7 @@ cn.axzo.workflow workflow-auto-gen - ${revision} + 1.3.3-SNAPSHOT diff --git a/workflow-engine-api/pom.xml b/workflow-engine-api/pom.xml index 7338f22b9..f7e35f4df 100644 --- a/workflow-engine-api/pom.xml +++ b/workflow-engine-api/pom.xml @@ -26,7 +26,6 @@ cn.axzo.workflow workflow-auto-gen - ${project.version} io.github.openfeign From ca48245c43bd24ed25105f4bebb780328bc930b8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Jun 2024 11:12:05 +0800 Subject: [PATCH 078/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20MQ=20=E7=9B=91=E6=8E=A7=E7=9B=B8=E5=85=B3=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessActivityApi.java | 3 +- .../bpmn/BpmnProcessActivityController.java | 2 +- .../StarterRPCInvokeMQConfiguration.java | 2 +- ...orkflowEngineStarterAutoConfiguration.java | 12 ++++-- ...WorkflowEngineStarterDefaultMQMonitor.java | 18 +++++++++ ...flowEngineStarterMQMonitorController.java} | 40 +++++++++++++------ 6 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/{DefaultMQMonitor.java => console/WorkflowEngineStarterMQMonitorController.java} (52%) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index d6f37d14e..8e49ba593 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -2,7 +2,6 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.generate.annotition.Management; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; @@ -25,6 +24,8 @@ public interface ProcessActivityApi { /** * 业务节点唤醒 + *

+ * TODO 接口需要合并,但需要考虑客户端与服务端不同版本间如何兼容 */ @GetMapping("/api/process/activity/old/trigger") CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index a7baabaa4..0bdb8b3cc 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -67,7 +67,7 @@ public class BpmnProcessActivityController implements ProcessActivityApi { @Override @RepeatSubmit public CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId) { - return trigger(triggerId, false); + return trigger(triggerId, true); } /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index ac1a73a9f..4a4a77528 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -69,7 +69,7 @@ public class StarterRPCInvokeMQConfiguration { public EventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { return new RpcInvokeEventProducer(rocketMQTemplate, DEFAULT_MODULE, - applicationName + "Starter", + applicationName + "_WE_Starter", EventProducer.Context.builder() .meta(RocketMQEventProducer.RocketMQMessageMeta.builder() .topic(DEFAULT_EVENT + activeProfile) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 360889667..1a5a1d190 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -22,7 +22,8 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; -import cn.axzo.workflow.starter.mq.monitor.DefaultMQMonitor; +import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; +import cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; @@ -132,7 +133,12 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean - public DefaultMQMonitor defaultMQMonitor() { - return new DefaultMQMonitor(); + public WorkflowEngineStarterMQMonitorController workflowEngineStarterMQMonitorController() { + return new WorkflowEngineStarterMQMonitorController(); + } + + @Bean + public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt) { + return new WorkflowEngineStarterDefaultMQMonitor(defaultMQAdminExt); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java new file mode 100644 index 000000000..9f23ae190 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -0,0 +1,18 @@ +package cn.axzo.workflow.starter.mq.monitor; + +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; + +/** + * 用于监控 Starter 关注的 Topic 相关的 Producer 与 Consumer 信息 + * + * @author wangli + * @since 2024/6/6 10:04 + */ +public class WorkflowEngineStarterDefaultMQMonitor { + + private final DefaultMQAdminExt defaultMQAdminExt; + + public WorkflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt) { + this.defaultMQAdminExt = defaultMQAdminExt; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java similarity index 52% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index 11fe1704a..112e57a32 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/DefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -1,8 +1,10 @@ -package cn.axzo.workflow.starter.mq.monitor; +package cn.axzo.workflow.starter.mq.monitor.console; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.azxo.framework.common.model.CommonResponse; import lombok.SneakyThrows; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -11,29 +13,43 @@ import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; +import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; + /** - * TODO + * Workflow Engine Starter MessageQueue Monitor Controller * * @author wangli - * @since 2024/6/5 17:49 + * @since 2024/6/6 10:04 */ @RestController -@RequestMapping("/web/workflow/engine/starter/monitor") -public class DefaultMQMonitor { - +@RequestMapping("/web/we/starter") +public class WorkflowEngineStarterMQMonitorController { + @Resource + private WorkflowEngineStarterProperties starterProperties; @Resource private DefaultMQAdminExt defaultMQAdminExt; + @Value("${spring.profiles.active}") + private String activeProfile; @SneakyThrows - @GetMapping("/test") - public CommonResponse monitor() { + @GetMapping("/monitor") + public CommonResponse> monitor() { + String topic = DEFAULT_EVENT + activeProfile; + String broadcastConsumerGroup = ""; Map result = new HashMap<>(); - result.put("examineTopicStats", defaultMQAdminExt.examineTopicStats("topic_workflow_engine_dev")); + result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); + result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); + result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); + + result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); + + System.getProperty(""); + if (starterProperties.getJoinContainerGroup()) { + + } + result.put("gid_senna", defaultMQAdminExt.examineConsumeStats("GID_senna_workflow_engine_debugging_consumer")); result.put("gid_senna_starter", defaultMQAdminExt.examineConsumeStats("GID_senna_workflow_engine_starter_debugging_consumer")); - result.put("brokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); - result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList("topic_workflow_engine_dev")); - result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo("topic_workflow_engine_dev")); defaultMQAdminExt.examineTopicConfig(System.getProperty("rocketmq.name-server"), "topic_workflow_engine_dev"); return CommonResponse.success(result); } From 5d1da6be43f456e34af66c28575ee92935f74eb0 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Jun 2024 14:02:12 +0800 Subject: [PATCH 079/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E9=BB=98=E8=AE=A4=E7=9A=84=20trigger=20=E7=9A=84?= =?UTF-8?q?=E5=85=A5=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/bpmn/BpmnProcessActivityController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index 65f73782e..b9601c36b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -69,7 +69,7 @@ public class BpmnProcessActivityController implements ProcessActivityApi { @RepeatSubmit public CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId) { log.info("业务节点唤醒 trigger2 ===>>>参数:{}", triggerId); - return trigger(triggerId, false); + return trigger(triggerId, true); } /** From fefbbac8c979eb4182f8ee9771d5e4b56215f046 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Jun 2024 15:35:06 +0800 Subject: [PATCH 080/210] =?UTF-8?q?update(REQ-2324)=20-=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=A1=B9=E7=9B=AE=E4=BD=BF=E7=94=A8=20Undertow=20?= =?UTF-8?q?=E9=85=8D=E5=90=88=20Nacos=20=E7=9A=84=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E6=97=B6=EF=BC=8C=E5=81=9C=E6=AD=A2=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E4=BC=9A=E5=AF=BC=E8=87=B4=E4=B8=80=E4=BA=9B=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E7=9A=84=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/common/hook/NacosShutdownHook.java | 26 +++ .../cloud/nacos/discovery/NacosWatch.java | 191 ++++++++++++++++++ .../client/naming/core/PushReceiver.java | 140 +++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java create mode 100644 workflow-engine-server/src/main/java/com/alibaba/cloud/nacos/discovery/NacosWatch.java create mode 100644 workflow-engine-server/src/main/java/com/alibaba/nacos/client/naming/core/PushReceiver.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java new file mode 100644 index 000000000..b2eaa31a8 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java @@ -0,0 +1,26 @@ +package cn.axzo.workflow.server.common.hook; + +import org.springframework.context.SmartLifecycle; + +/** + * TODO + * + * @author wangli + * @since 2024/6/6 14:35 + */ +public class NacosShutdownHook implements SmartLifecycle { + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + @Override + public boolean isRunning() { + return false; + } +} diff --git a/workflow-engine-server/src/main/java/com/alibaba/cloud/nacos/discovery/NacosWatch.java b/workflow-engine-server/src/main/java/com/alibaba/cloud/nacos/discovery/NacosWatch.java new file mode 100644 index 000000000..bfeeb41ed --- /dev/null +++ b/workflow-engine-server/src/main/java/com/alibaba/cloud/nacos/discovery/NacosWatch.java @@ -0,0 +1,191 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.discovery; + +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.cloud.nacos.NacosServiceManager; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.Event; +import com.alibaba.nacos.api.naming.listener.EventListener; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.alibaba.nacos.api.naming.pojo.Instance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.SmartLifecycle; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author xiaojing + * @author yuhuangbin + */ +public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycle { + + private static final Logger log = LoggerFactory.getLogger(NacosWatch.class); + + private Map listenerMap = new ConcurrentHashMap<>(16); + + private final AtomicBoolean running = new AtomicBoolean(false); + + private final AtomicLong nacosWatchIndex = new AtomicLong(0); + + private ApplicationEventPublisher publisher; + + private ScheduledFuture watchFuture; + + private NacosServiceManager nacosServiceManager; + + private final NacosDiscoveryProperties properties; + + private final ThreadPoolTaskScheduler taskScheduler; + + public NacosWatch(NacosServiceManager nacosServiceManager, + NacosDiscoveryProperties properties, + ObjectProvider taskScheduler) { + this.nacosServiceManager = nacosServiceManager; + this.properties = properties; + this.taskScheduler = taskScheduler.stream().findAny() + .orElseGet(NacosWatch::getTaskScheduler); + } + + private static ThreadPoolTaskScheduler getTaskScheduler() { + ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); + taskScheduler.setBeanName("Nacos-Watch-Task-Scheduler"); + taskScheduler.initialize(); + return taskScheduler; + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { + this.publisher = publisher; + } + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void stop(Runnable callback) { + this.stop(); + callback.run(); + } + + @Override + public void start() { + if (this.running.compareAndSet(false, true)) { + EventListener eventListener = listenerMap.computeIfAbsent(buildKey(), + event -> new EventListener() { + @Override + public void onEvent(Event event) { + if (event instanceof NamingEvent) { + List instances = ((NamingEvent) event) + .getInstances(); + Optional instanceOptional = selectCurrentInstance( + instances); + instanceOptional.ifPresent(currentInstance -> { + resetIfNeeded(currentInstance); + }); + } + } + }); + + NamingService namingService = nacosServiceManager + .getNamingService(properties.getNacosProperties()); + try { + namingService.subscribe(properties.getService(), properties.getGroup(), + Arrays.asList(properties.getClusterName()), eventListener); + } catch (Exception e) { + log.error("namingService subscribe failed, properties:{}", properties, e); + } + + this.watchFuture = this.taskScheduler.scheduleWithFixedDelay( + this::nacosServicesWatch, this.properties.getWatchDelay()); + } + } + + private String buildKey() { + return String.join(":", properties.getService(), properties.getGroup()); + } + + private void resetIfNeeded(Instance instance) { + if (!properties.getMetadata().equals(instance.getMetadata())) { + properties.setMetadata(instance.getMetadata()); + } + } + + private Optional selectCurrentInstance(List instances) { + return instances.stream() + .filter(instance -> properties.getIp().equals(instance.getIp()) + && properties.getPort() == instance.getPort()) + .findFirst(); + } + + @Override + public void stop() { + if (this.running.compareAndSet(true, false)) { + if (this.watchFuture != null) { + // shutdown current user-thread, + // then the other daemon-threads will terminate automatic. + this.taskScheduler.shutdown(); + this.watchFuture.cancel(true); + } + + EventListener eventListener = listenerMap.get(buildKey()); + try { + NamingService namingService = nacosServiceManager + .getNamingService(properties.getNacosProperties()); + namingService.unsubscribe(properties.getService(), properties.getGroup(), + Arrays.asList(properties.getClusterName()), eventListener); + } catch (Exception e) { + log.error("namingService unsubscribe failed, properties:{}", properties, + e); + } + } + } + + @Override + public boolean isRunning() { + return this.running.get(); + } + + @Override + public int getPhase() { + return Integer.MAX_VALUE - 1; + } + + public void nacosServicesWatch() { + + // nacos doesn't support watch now , publish an event every 30 seconds. + this.publisher.publishEvent( + new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement())); + + } + +} diff --git a/workflow-engine-server/src/main/java/com/alibaba/nacos/client/naming/core/PushReceiver.java b/workflow-engine-server/src/main/java/com/alibaba/nacos/client/naming/core/PushReceiver.java new file mode 100644 index 000000000..dd9e4e795 --- /dev/null +++ b/workflow-engine-server/src/main/java/com/alibaba/nacos/client/naming/core/PushReceiver.java @@ -0,0 +1,140 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.client.naming.core; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.common.lifecycle.Closeable; +import com.alibaba.nacos.common.utils.IoUtils; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.common.utils.ThreadUtils; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.nio.charset.Charset; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; + +import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER; + +/** + * Push receiver. + * + * @author xuanyin + */ +public class PushReceiver implements Runnable, Closeable { + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + private static final int UDP_MSS = 64 * 1024; + + private ScheduledExecutorService executorService; + + private DatagramSocket udpSocket; + + private HostReactor hostReactor; + + private volatile boolean closed = false; + + public PushReceiver(HostReactor hostReactor) { + try { + this.hostReactor = hostReactor; + this.udpSocket = new DatagramSocket(); + this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setDaemon(true); + thread.setName("com.alibaba.nacos.naming.push.receiver"); + return thread; + } + }); + + this.executorService.execute(this); + } catch (Exception e) { + NAMING_LOGGER.error("[NA] init udp socket failed", e); + } + } + + @Override + public void run() { + while (!closed) { + try { + + // byte[] is initialized with 0 full filled by default + byte[] buffer = new byte[UDP_MSS]; + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + + udpSocket.receive(packet); + + String json = new String(IoUtils.tryDecompress(packet.getData()), UTF_8).trim(); + NAMING_LOGGER.info("received push data: " + json + " from " + packet.getAddress().toString()); + + PushPacket pushPacket = JacksonUtils.toObj(json, PushPacket.class); + String ack; + if ("dom".equals(pushPacket.type) || "service".equals(pushPacket.type)) { + hostReactor.processServiceJson(pushPacket.data); + + // send ack to server + ack = "{\"type\": \"push-ack\"" + ", \"lastRefTime\":\"" + pushPacket.lastRefTime + "\", \"data\":" + + "\"\"}"; + } else if ("dump".equals(pushPacket.type)) { + // dump data to server + ack = "{\"type\": \"dump-ack\"" + ", \"lastRefTime\": \"" + pushPacket.lastRefTime + "\", \"data\":" + + "\"" + StringUtils.escapeJavaScript(JacksonUtils.toJson(hostReactor.getServiceInfoMap())) + + "\"}"; + } else { + // do nothing send ack only + ack = "{\"type\": \"unknown-ack\"" + ", \"lastRefTime\":\"" + pushPacket.lastRefTime + + "\", \"data\":" + "\"\"}"; + } + + udpSocket.send(new DatagramPacket(ack.getBytes(UTF_8), ack.getBytes(UTF_8).length, + packet.getSocketAddress())); + } catch (Exception e) { + if (closed) { + return; + } + NAMING_LOGGER.error("[NA] error while receiving push data", e); + } + } + } + + @Override + public void shutdown() throws NacosException { + String className = this.getClass().getName(); + NAMING_LOGGER.info("{} do shutdown begin", className); + ThreadUtils.shutdownThreadPool(executorService, NAMING_LOGGER); + closed = true; + udpSocket.close(); + NAMING_LOGGER.info("{} do shutdown stop", className); + } + + public static class PushPacket { + + public String type; + + public long lastRefTime; + + public String data; + } + + public int getUdpPort() { + return this.udpSocket.getLocalPort(); + } +} From 72b172788ac3db96eb1add5e4bbc47309f407f4c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Jun 2024 11:08:37 +0800 Subject: [PATCH 081/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=B1=BB=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java index 510d6d221..18e70a31c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java @@ -9,7 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * TODO + * 对 CommandContext 中的 WorkflowEngineException 进行日志降级 * * @author wangli * @since 2024/5/21 09:46 From f60a0c820618dcafe67a65114e718d34889efbc8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Jun 2024 14:55:05 +0800 Subject: [PATCH 082/210] =?UTF-8?q?update(REQ-2516)=20-=20MQ=20=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E6=94=AF=E6=8C=81=E5=A4=9A=E4=B8=AA=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/WorkflowRequestInterceptor.java | 4 ++++ .../workflow/common/constant/BpmnConstants.java | 1 + workflow-engine-core/pom.xml | 4 ++++ .../impl/BpmnProcessInstanceServiceImpl.java | 8 ++++++++ ...BroadcastListenerConfigurationProperties.java | 14 ++++++++++++++ .../starter/StarterBroadcastMQConfiguration.java | 4 ++-- .../starter/StarterRPCInvokeMQConfiguration.java | 4 ++-- .../filter/InnerFilterDefinitionKeyInner.java | 3 ++- ...hipInner.java => InnerFilterMQOwnerShip.java} | 16 ++++++++-------- 9 files changed, 45 insertions(+), 13 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/{InnerFilterMQOwnerShipInner.java => InnerFilterMQOwnerShip.java} (66%) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java index bd7533f16..43029b70b 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowRequestInterceptor.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.client.config; import feign.RequestInterceptor; import feign.RequestTemplate; import feign.Target; +import org.springframework.beans.factory.annotation.Value; /** * 通用的 Feign 请求拦截器 @@ -11,6 +12,8 @@ import feign.Target; * @since 2024/2/4 15:33 */ public class WorkflowRequestInterceptor implements RequestInterceptor { + @Value("${spring.application.name}") + private String applicationName; private final String serviceVersion; public WorkflowRequestInterceptor(String serviceVersion) { @@ -31,6 +34,7 @@ public class WorkflowRequestInterceptor implements RequestInterceptor { || apiClassPath.contains("cn.axzo.workflow.client.feign.manage")) { requestTemplate.header(HEADER_HTTP_CLIENT, HEADER_HTTP_CLIENT_VALUE); requestTemplate.header(HEADER_API_VERSION, serviceVersion); + requestTemplate.header(HEADER_SERVER_NAME, applicationName); } } } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index ffdd11d80..9a3a41d7b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -11,6 +11,7 @@ public interface BpmnConstants { */ String FLOWABLE_SKIP_EXPRESSION_ENABLE = "[_FLOWABLE_SKIP_EXPRESSION_ENABLED_]"; String MQ_UNIQUE_ID = "[_MQ_UNIQUE_ID_]"; + String PROCESS_OWNERSHIP_APPLICATION = "[_PROCESS_OWNERSHIP_APPLICATION_]"; String WORKFLOW_ENGINE_VERSION = "[_WORKFLOW_ENGINE_VERSION_]"; String INTERNAL_INITIATOR = "[_INTERNAL_INITIATOR_]"; @Deprecated diff --git a/workflow-engine-core/pom.xml b/workflow-engine-core/pom.xml index 5300ec602..00e1896d7 100644 --- a/workflow-engine-core/pom.xml +++ b/workflow-engine-core/pom.xml @@ -97,5 +97,9 @@ org.apache.maven maven-artifact + + jakarta.servlet + jakarta.servlet-api + diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 5f8752afd..92e63cffa 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -86,9 +86,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Nullable; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.ArrayList; import java.util.Collections; @@ -102,6 +105,7 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY; @@ -112,6 +116,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_AG import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_WORKSPACE_TYPE; import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.PENDING_TEMPLATE_VARIABLE; +import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_OWNERSHIP_APPLICATION; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoPassed; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoRejection; @@ -320,6 +325,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic dto.getVariables().put(INTERNAL_PROCESS_AGENT, StringUtils.isNotBlank(definition.getTenantId())); dto.getVariables().put(CREATE_INSTANCE_PARAMS, JSONUtil.toJsonStr(dto)); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + dto.getVariables().put(PROCESS_OWNERSHIP_APPLICATION, request.getHeader(HEADER_SERVER_NAME)); +// dto.getVariables().put(MQ_OWNERSHIP_APPLICATION, ); // if (Objects.nonNull(dto.getNextApprover())) { // BpmnTaskDelegateAssigner nextApprover = dto.getNextApprover(); // nextApprover.setTenantId(Objects.nonNull(nextApprover.getTenantId()) ? nextApprover.getTenantId diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java index 28894bdfc..57079bd3c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java @@ -22,6 +22,12 @@ public class BroadcastListenerConfigurationProperties { * 是否开启根据应用名过滤 MQ 事件 */ private Boolean enableFilterApplicationName = false; + + /** + * 仅过滤这些应用名称创建的流程 + */ + private Set filterApplicationNames = new HashSet<>(); + /** * 是否开启根据业务 ID 集合过滤 MQ 事件 */ @@ -69,6 +75,14 @@ public class BroadcastListenerConfigurationProperties { this.enableFilterApplicationName = enableFilterApplicationName; } + public Set getFilterApplicationNames() { + return filterApplicationNames; + } + + public void setFilterApplicationNames(Set filterApplicationNames) { + this.filterApplicationNames = filterApplicationNames; + } + public Boolean getEnableFilterDefinitionKey() { return enableFilterDefinitionKey; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 291cddd3c..d8b0ebe0a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -12,7 +12,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEve import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKeyInner; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShipInner; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; import com.google.common.collect.ImmutableList; import org.apache.rocketmq.common.message.MessageExt; @@ -112,7 +112,7 @@ public class StarterBroadcastMQConfiguration { @Override public void afterPropertiesSet() { this.filters = ImmutableList.of( - new InnerFilterMQOwnerShipInner(starterProperties, applicationName), + new InnerFilterMQOwnerShip(starterProperties, applicationName), new InnerFilterDefinitionKeyInner(starterProperties), new InnerFilterExtension(businessFilterProvider)); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 4a4a77528..57edb2a74 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -10,7 +10,7 @@ import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShipInner; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; @@ -185,7 +185,7 @@ public class StarterRPCInvokeMQConfiguration { @Override public void afterPropertiesSet() { - this.filter = new InnerFilterMQOwnerShipInner(starterProperties, applicationName); + this.filter = new InnerFilterMQOwnerShip(starterProperties, applicationName); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java index 316400eba..8a0554f07 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; +import cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; @@ -11,7 +12,7 @@ import java.util.Map; import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; /** - * TODO + * 对 {@link BroadcastListenerConfigurationProperties#filterProcessDefinitionKeys} 的实现 * * @author wangli * @since 2024/6/4 17:06 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShipInner.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java similarity index 66% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShipInner.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java index e68a4f9ee..3f105d98a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShipInner.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; +import cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; @@ -7,25 +8,23 @@ import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import java.util.Map; -import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION; /** - * TODO + * 对 {@link BroadcastListenerConfigurationProperties#filterApplicationNames} 的实现 * * @author wangli * @since 2024/6/4 17:06 */ -public class InnerFilterMQOwnerShipInner implements InnerMessageQueueHandleBeforeFilter { - private final Logger log = LoggerFactory.getLogger(InnerFilterMQOwnerShipInner.class); +public class InnerFilterMQOwnerShip implements InnerMessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterMQOwnerShip.class); private final WorkflowEngineStarterProperties properties; - private final String applicationName; - public InnerFilterMQOwnerShipInner(WorkflowEngineStarterProperties properties, String applicationName) { + public InnerFilterMQOwnerShip(WorkflowEngineStarterProperties properties, String applicationName) { this.properties = properties; - this.applicationName = applicationName; + this.properties.getBroadcast().getFilterApplicationNames().add(applicationName); } @Override @@ -35,7 +34,8 @@ public class InnerFilterMQOwnerShipInner implements InnerMessageQueueHandleBefor } Map headers = message.getProperties(); String mqOwnerShip = headers.getOrDefault(MQ_OWNERSHIP_APPLICATION, null); - if (StringUtils.hasText(mqOwnerShip) && Objects.equals(mqOwnerShip, applicationName)) { + + if (StringUtils.hasText(mqOwnerShip) && properties.getBroadcast().getFilterApplicationNames().contains(mqOwnerShip)) { return false; } log.info("The broadcast message does not attribute the message, will be ignored. messageId: {}, mq-ownership-application: {}", message.getMsgId(), mqOwnerShip); From 7148811ccf1db97d1aa8577087d2db61a2660b96 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Jun 2024 18:47:56 +0800 Subject: [PATCH 083/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E5=BC=95=E5=85=A5=20Javaparser=20=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 +++ .../common/annotation/Manageable.java | 10 +++++ workflow-engine-support/pom.xml | 23 ++++++++++ .../workflow/support/api/CodeGeneration.java | 45 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/Manageable.java create mode 100644 workflow-engine-support/pom.xml create mode 100644 workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java diff --git a/pom.xml b/pom.xml index 84449fd88..c411bf41e 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,7 @@ 2.0.0 3.7.1 3.2.5 + 3.26.0 @@ -109,6 +110,11 @@ maven-artifact ${apache-maven.version} + + com.github.javaparser + javaparser-core + ${javaparse.version} + @@ -154,5 +160,6 @@ workflow-engine-core workflow-engine-server workflow-engine-spring-boot-starter + workflow-engine-support diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/Manageable.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/Manageable.java new file mode 100644 index 000000000..f8d9622a1 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/annotation/Manageable.java @@ -0,0 +1,10 @@ +package cn.axzo.workflow.common.annotation; + +/** + * 控制接口是否调用受限,标记了注解的方法,表示受控,不允许暴露给客户端使用 + * + * @author wangli + * @since 2024/6/7 18:21 + */ +public @interface Manageable { +} diff --git a/workflow-engine-support/pom.xml b/workflow-engine-support/pom.xml new file mode 100644 index 000000000..6a40185c4 --- /dev/null +++ b/workflow-engine-support/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + cn.axzo.workflow + workflow-engine + ${revision} + + ${revision} + workflow-engine-support + jar + Workflow Engine Support + + + com.github.javaparser + javaparser-core + + + cn.axzo.workflow + workflow-engine-spring-boot-starter + + + diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java new file mode 100644 index 000000000..b19ea961e --- /dev/null +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java @@ -0,0 +1,45 @@ +package cn.axzo.workflow.support.api; + +import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; +import cn.axzo.workflow.starter.WorkflowEngineStarterAutoConfiguration; +import com.github.javaparser.ParseResult; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.printer.DefaultPrettyPrinter; +import com.github.javaparser.printer.Printer; +import com.github.javaparser.utils.CodeGenerationUtils; +import com.github.javaparser.utils.SourceRoot; +import lombok.SneakyThrows; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * TODO + * + * @author wangli + * @since 2024/6/7 17:14 + */ +public class CodeGeneration { + + @SneakyThrows + public static void main(String[] args) { + Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineClientAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/client/feign/"); + SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); + sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); + Printer printer = new DefaultPrettyPrinter(); + sourceRoot.setPrinter(printer::print); + + List> parseResults = sourceRoot.tryToParse(); + List compilationUnits = sourceRoot.getCompilationUnits(); + compilationUnits.forEach(compilationUnit -> { + System.out.println("compilationUnit = " + compilationUnit); + }); + + Path outputCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineStarterAutoConfiguration.class).resolve(Paths.get("src/main/java/cn/axzo/workflow/starter/api")); + SourceRoot outputCodeSR = new SourceRoot(outputCodeRoot); + outputCodeSR.saveAll(StandardCharsets.UTF_8); + } +} From d491169c78289523234a792031c80fee0547dd8f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Jun 2024 18:50:18 +0800 Subject: [PATCH 084/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E5=BC=95=E5=85=A5=20Javaparser=20=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/workflow/support/api/CodeGeneration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java index b19ea961e..32714520c 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java @@ -38,6 +38,7 @@ public class CodeGeneration { System.out.println("compilationUnit = " + compilationUnit); }); + // https://www.jianshu.com/p/04b413c97988 Path outputCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineStarterAutoConfiguration.class).resolve(Paths.get("src/main/java/cn/axzo/workflow/starter/api")); SourceRoot outputCodeSR = new SourceRoot(outputCodeRoot); outputCodeSR.saveAll(StandardCharsets.UTF_8); From 15323a6752ba01e5585ddeed2d5aa0c2512141d1 Mon Sep 17 00:00:00 2001 From: wangli Date: Mon, 10 Jun 2024 22:02:40 +0800 Subject: [PATCH 085/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20Javaparser=20=E7=94=9F=E6=88=90=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/support/api/CodeGeneration.java | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java index 32714520c..693ce34f3 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java @@ -1,15 +1,25 @@ package cn.axzo.workflow.support.api; import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.starter.WorkflowEngineStarterAutoConfiguration; import com.github.javaparser.ParseResult; import com.github.javaparser.ParserConfiguration; import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.expr.NormalAnnotationExpr; import com.github.javaparser.printer.DefaultPrettyPrinter; import com.github.javaparser.printer.Printer; import com.github.javaparser.utils.CodeGenerationUtils; import com.github.javaparser.utils.SourceRoot; import lombok.SneakyThrows; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -35,12 +45,34 @@ public class CodeGeneration { List> parseResults = sourceRoot.tryToParse(); List compilationUnits = sourceRoot.getCompilationUnits(); compilationUnits.forEach(compilationUnit -> { - System.out.println("compilationUnit = " + compilationUnit); +// System.out.println("compilationUnit = " + compilationUnit); }); // https://www.jianshu.com/p/04b413c97988 Path outputCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineStarterAutoConfiguration.class).resolve(Paths.get("src/main/java/cn/axzo/workflow/starter/api")); SourceRoot outputCodeSR = new SourceRoot(outputCodeRoot); outputCodeSR.saveAll(StandardCharsets.UTF_8); + + CompilationUnit compilationUnit = new CompilationUnit(); + ClassOrInterfaceDeclaration workflowCoreServiceTest = compilationUnit.addInterface("WorkflowCoreServiceTest").setPublic(true); + workflowCoreServiceTest.setInterface(true); + MethodDeclaration a = workflowCoreServiceTest.addMethod("a", Modifier.Keyword.PUBLIC).removeBody(); + a.setJavadocComment("创建审批流程"); + Parameter dto = a.addAndGetParameter(BpmnProcessInstanceCreateDTO.class, "dto"); + dto.addAnnotation(Validated.class).addAnnotation(RequestBody.class); + a.setType(String.class); + + NormalAnnotationExpr postMapping = a.addAndGetAnnotation(PostMapping.class); + postMapping.addPair("value", "/api/process/instance/create"); +// postMapping.setName("/api/process/instance/create"); + + NormalAnnotationExpr invokeMode = a.addAndGetAnnotation(InvokeMode.class); + invokeMode.addPair("value", "SYNC"); + +// compilationUnit.setPackageDeclaration("cn.axzo.workflow.starter.api"); + compilationUnit.addImport(BpmnProcessInstanceCreateDTO.class); + + String string = workflowCoreServiceTest.toString(); + System.out.println("string = " + string); } } From ce23fcbc698798d068ac76a435b87a5d60fc5dd2 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 11 Jun 2024 17:59:50 +0800 Subject: [PATCH 086/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=88=A9?= =?UTF-8?q?=E7=94=A8=20javaparser=20=E7=94=9F=E6=88=90=E5=8F=AF=E7=94=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 +- workflow-engine-api/pom.xml | 4 +- .../feign/bpmn/ProcessDefinitionApi.java | 2 + .../client/feign/bpmn/ProcessInstanceApi.java | 16 +- .../client/feign/bpmn/ProcessModelApi.java | 2 + .../client/feign/bpmn/ProcessTaskApi.java | 12 +- .../client/feign/bpmn/ProcessVariableApi.java | 2 + .../feign/manage/ProcessCategoryApi.java | 4 +- .../client/feign/manage/ProcessConfigApi.java | 4 +- .../server/controller/web/TestController.java | 2 +- workflow-engine-spring-boot-starter/pom.xml | 4 +- .../starter/api/WorkflowCoreService.java | 248 +++++++++-- .../starter/api/WorkflowCoreService_Gen.java | 299 ------------- .../starter/api/WorkflowManageService.java | 26 ++ .../feign/ext/WorkflowEngineStarterFeign.java | 25 ++ ...rkflowEngineStarterFeignConfiguration.java | 12 + .../ext/WorkflowEngineStarterTarget.java | 27 ++ .../ext/WorkflowEngineStarterTargeter.java | 36 ++ .../src/main/java/feign/ReflectiveFeign.java | 415 ++++++++++++++++++ .../workflow/support/api/CodeGeneration.java | 78 ---- .../support/api/CoreServiceCodeGenerator.java | 190 ++++++++ .../api/ManageServiceCodeGenerator.java | 166 +++++++ 22 files changed, 1161 insertions(+), 421 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java delete mode 100644 workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java create mode 100644 workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java create mode 100644 workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java diff --git a/pom.xml b/pom.xml index c411bf41e..2947d97f2 100644 --- a/pom.xml +++ b/pom.xml @@ -65,11 +65,11 @@ workflow-engine-core ${project.version} - + ${project.groupId} workflow-engine-server @@ -136,11 +136,11 @@ mapstruct-processor ${mapstruct.version} - + diff --git a/workflow-engine-api/pom.xml b/workflow-engine-api/pom.xml index f7e35f4df..7f088af3c 100644 --- a/workflow-engine-api/pom.xml +++ b/workflow-engine-api/pom.xml @@ -23,10 +23,10 @@ workflow-engine-common ${project.version} - + io.github.openfeign feign-httpclient diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java index 56fc309d0..a1bde7459 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; @@ -24,6 +25,7 @@ import javax.validation.constraints.NotNull; * @since 2023/9/21 16:25 */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@Manageable public interface ProcessDefinitionApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index 2bab954b1..f634d5714 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; @@ -16,7 +18,6 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAd import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import cn.axzo.workflow.generate.annotition.GenService; import cn.azxo.framework.common.model.CommonResponse; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; @@ -35,13 +36,14 @@ import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * 流程实例 API * * @author wangli * @since 2023/9/21 16:26 */ -@GenService(genPkgName = "cn.axzo.workflow.starter.api") @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessInstanceApi { /** @@ -51,6 +53,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "查询所有的审批流") @PostMapping("/api/process/instance/page/all") + @Manageable CommonResponse> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); /** @@ -58,6 +61,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "我发起的审批列表") @PostMapping("/api/process/instance/page/my") + @Manageable CommonResponse> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); /** @@ -73,6 +77,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") @PostMapping("/api/process/instance/create") + @InvokeMode(SYNC) CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); /** @@ -83,6 +88,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "创建审批流程并带上表单") @PostMapping("/api/process/instance/form/create") + @Manageable CommonResponse createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); /** @@ -149,6 +155,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例") @PutMapping("/api/process/instance/status/update") + @Manageable CommonResponse updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status); @@ -161,6 +168,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "获取审批流程实例的运行图") @GetMapping("/api/process/instance/graphical") + @Manageable CommonResponse processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -171,6 +179,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "推断指定流程实例的所有节点执行顺序") @GetMapping("/api/process/instance/node/forecasting") + @Manageable CommonResponse> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -183,6 +192,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") @GetMapping("/api/process/instance/node/filter/forecasting") + @Manageable CommonResponse> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @@ -207,6 +217,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "查询实例的租户集合") @GetMapping("/api/process/instance/tenant/ids") + @Manageable CommonResponse> getTenantIds(); /** @@ -216,5 +227,6 @@ public interface ProcessInstanceApi { */ @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") @PostMapping("/api/process/instance/check/approver") + @Manageable CommonResponse checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index 4f203e3f7..0da4f77d0 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; @@ -29,6 +30,7 @@ import java.util.List; * @since 2023/9/21 15:47 */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@Manageable public interface ProcessModelApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index d2f817179..8193ab5d8 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; @@ -17,7 +18,6 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstance import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import cn.axzo.workflow.generate.annotition.GenService; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; @@ -41,7 +41,6 @@ import java.util.Map; * @since 2023/9/21 16:26 */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) -@GenService(genPkgName = "cn.axzo.workflow.starter.api") public interface ProcessTaskApi { /** @@ -49,6 +48,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "待审核列表") @GetMapping("/api/process/task/page/todo") + @Manageable CommonResponse> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** @@ -56,6 +56,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "已完成的审批列表") @GetMapping("/api/process/task/page/done") + @Manageable CommonResponse> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** @@ -65,6 +66,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/flat") + @Manageable CommonResponse> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -75,6 +77,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/group") + @Manageable CommonResponse> getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -83,6 +86,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "获取实例正在审核的人列表") @GetMapping("/api/process/task/active/list") + @Manageable CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); @@ -171,6 +175,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "添加附件") @PostMapping("/api/process/task/attachment") + @Manageable CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); /** @@ -191,6 +196,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "审批流程催办") @PostMapping("/api/process/task/remind") + @Manageable CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); /** @@ -220,6 +226,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/find") + @Manageable CommonResponse findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); @@ -230,6 +237,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/batch/find") + @Manageable CommonResponse> findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java index a6fe0f77d..f9c88967d 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -17,6 +18,7 @@ import javax.validation.constraints.NotBlank; * 流程变量api */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@Manageable public interface ProcessVariableApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index 0daf1062f..0536f56ed 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.manage; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; @@ -9,7 +10,6 @@ import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; import cn.axzo.workflow.common.model.response.category.CategoryItemVO; -import cn.axzo.workflow.generate.annotition.Management; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; @@ -33,7 +33,7 @@ import java.util.List; */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) -@Management +@Manageable public interface ProcessCategoryApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java index fb5915e82..b9727a802 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java @@ -1,7 +1,7 @@ package cn.axzo.workflow.client.feign.manage; import cn.axzo.workflow.client.config.CommonFeignConfiguration; -import cn.axzo.workflow.generate.annotition.Management; +import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -19,7 +19,7 @@ import java.util.List; */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) -@Management +@Manageable public interface ProcessConfigApi { /** diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index cbbbfa669..50cd4e9ba 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -217,7 +217,7 @@ public class TestController { RestBpmnProcessVariable variable = new RestBpmnProcessVariable(); variable.setName("testVar"); variable.setValue("testValue"); - workflowCoreService.createVariable(processInstanceId, variable); +// workflowCoreService.createVariable(processInstanceId, variable); return CommonResponse.success(null); } diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index 93f82f89f..e19372f30 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -19,10 +19,10 @@ cn.axzo.workflow workflow-engine-api - + cn.axzo.framework.rocketmq axzo-common-rocketmq diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 6f507a43b..d7abe057d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,11 +1,18 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.util.ThreadUtil; @@ -15,7 +22,6 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -28,44 +34,233 @@ import java.util.Map; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; - /** - * 模拟生成的受限访问的接口定义 - * - * @author wangli - * @since 2024/5/28 16:12 + * Workflow Engine Starter Core Service */ -@FeignClient(name = "workflow-engine-starter", - url = "${axzo.service.workflow-engine:workflow-engine:8080}", - configuration = WorkflowEngineStarterFeignConfiguration.class) +@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { + /** + * 业务节点唤醒 + *

+ * TODO 接口需要合并,但需要考虑客户端与服务端不同版本间如何兼容 + */ + @GetMapping("/api/process/activity/old/trigger") + Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); + + @Operation(summary = "业务节点唤醒") + @GetMapping("/api/process/activity/trigger") + Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, @RequestParam(required = false, defaultValue = "false") Boolean async); + + /** + * 业务节点设置审批人, 不支持重复设置 + * + * @param dto + * @return + */ + @PostMapping("/api/process/activity/assignee/set") + @Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人") + Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto); + + /** + * 创建审批流程 + * + *

+     *   MQ 触发规则:
+     *     1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
+     *     2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
+     * 
+ * + * @param dto {@link BpmnProcessInstanceCreateDTO} + */ + @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") @PostMapping("/api/process/instance/create") @InvokeMode(SYNC) String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); - @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") - @PostMapping("/api/process/task/approve") - Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + /** + * 发起人主动撤回审核 + * + *
+     *   MQ 触发规则:
+     *     1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
+     *     2. 当前流程实例会触发 process-instance-cancelled 事件
+     * 
+ * + * @param dto {@link BpmnProcessInstanceCancelDTO} + * @return + */ + @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件") + @DeleteMapping("/api/process/instance/cancel") + Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto); - @Operation(summary = "获得流程实例") - @GetMapping("/api/process/instance/get") - BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); - - @Operation(summary = "获取指定流程实例的流程变量") - @GetMapping("/api/process/instance/cooperation-org") - Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - - @Operation(summary = "为指定流程新增变量") - @GetMapping("/api/process/variable/create/{executionId}") - void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, - @RequestBody @Validated RestBpmnProcessVariable restVariable); + /** + * 中止流程实例 + * + * @param dto + * @return + */ + @Operation(summary = "中止流程实例") + @DeleteMapping("/api/process/instance/abort") + Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto); + /** + * 批量中止流程实例 + * + * @param dtos + * @return + */ @Operation(summary = "批量中止流程实例") @DeleteMapping("/api/process/instance/batch/abort") BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); + /** + * 抄送流程实例 + * + * @param dto + * @return + */ + @Operation(summary = "抄送流程实例") + @PostMapping("/api/process/instance/carbon-copy") + Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); + + /** + * 获得流程实例 + * + * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询 + * @return 流程实例, 租户Id不必传 + */ + @Operation(summary = "获得流程实例") + @GetMapping("/api/process/instance/get") + BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + + /** + * 获取指定流程实例的流程变量 + * + * @param processInstanceId + * @param tenantId + * @return + */ + @Operation(summary = "获取指定流程实例的流程变量") + @GetMapping("/api/process/instance/cooperation-org") + Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + @GetMapping("/api/process/job/dead-letter/resume") + Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + + /** + * 同意 + * + *
+     * MQ 触发规则:
+     *  1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
+     *  如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
+     *  2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
+     *  2.2. 流程实例正常结束会触发 process-instance-completed 事件
+     * 
+ */ + @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") + @PostMapping("/api/process/task/approve") + Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + /** + * 批量同意 + * + * @param dtos + * @return + */ + @Operation(summary = "批量同意") + @PostMapping("/api/process/task/batch/approve") + BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); + + /** + * 驳回 + * + *
+     * MQ 触发规则:
+     *   1. 当前审批任务会触发 process-task-deleted 事件
+     *   2. 当前流程实例会触发 process-instance-rejected 事件
+     * 
+ */ + @Operation(summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件") + @PostMapping("/api/process/task/reject") + Boolean rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + /** + * 批量驳回 + * + * @param dtos 批量请求参数 + * @return + */ + @PostMapping("/api/process/task/batch/reject") + BatchOperationResultVO batchRejectTask(@Validated @RequestBody List dtos); + + /** + * 转交 + * + * @param dto + * @return + */ + @Operation(summary = "直接修改审批任务的审批人") + @PostMapping("/api/process/task/transfer") + Boolean transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); + + /** + * 批量转交 + * + * @param dtos + * @return + */ + @Operation(summary = "批量修改审批任务的审批人") + @PostMapping("/api/process/task/batch/transfer") + BatchOperationResultVO batchTransferTask(@Validated @RequestBody List dtos); + + /** + * 评论 + * + * @param dto 评论请求参数 + * @return + */ + @Operation(summary = "审批流程评论") + @PostMapping("/api/process/task/comment") + Boolean commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); + + /** + * 加签 + * + * @param dto 加签请求参数 + * @return + */ + @Operation(summary = "审批流程加签") + @PostMapping("/api/process/task/countersign") + Boolean countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); + + /** + * 暂停流程任务,并创建机器人节点,等待业务推动 + * + * @param dto + * @return 返回机器人节点任务 ID + */ + @Operation(summary = "创建机器人节点, 暂停流程任务") + @PostMapping("/api/process/task/robot/create") + String createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); + + /** + * 完成机器人节点 + * + * @param dto + * @return + */ + @Operation(summary = "完成机器人节点, 继续流程任务") + @PostMapping("/api/process/task/robot/complete") + Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); + + /** + * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 + *
+     * workflowCoreService.async().createProcessInstance();
+     * 
+ */ default WorkflowCoreService sync() { ThreadUtil.set(SYNC); return this; @@ -75,5 +270,4 @@ public interface WorkflowCoreService { ThreadUtil.set(ASYNC); return this; } - } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java deleted file mode 100644 index 94392484c..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService_Gen.java +++ /dev/null @@ -1,299 +0,0 @@ -// --auto generated by workflow auto-gen plugin-- -package cn.axzo.workflow.starter.api; - -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import cn.azxo.framework.common.model.CommonResponse; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.swagger.v3.oas.annotations.Operation; -import java.lang.Boolean; -import java.lang.Integer; -import java.lang.Object; -import java.lang.String; -import java.lang.Void; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; - -public interface WorkflowCoreService_Gen { - @Operation( - summary = "待审核列表" - ) - @GetMapping("/api/process/task/page/todo") - CommonResponse> getTodoTaskPage( - @Validated @RequestBody BpmnTaskPageSearchDTO dto); - - @Operation( - summary = "已完成的审批列表" - ) - @GetMapping("/api/process/task/page/done") - CommonResponse> getDoneTaskPage( - @Validated @RequestBody BpmnTaskPageSearchDTO dto); - - @Operation( - summary = "获取指定流程实例的审批过程信息" - ) - @GetMapping("/api/process/task/list/flat") - CommonResponse> getTaskListFlatByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - - @Operation( - summary = "获取指定流程实例的审批过程信息" - ) - @GetMapping("/api/process/task/list/group") - CommonResponse> getTaskListGroupByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - - @Operation( - summary = "获取实例正在审核的人列表" - ) - @GetMapping("/api/process/task/active/list") - CommonResponse> getActiveTasksByProcessInstanceId( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @NotBlank(message = "租户不能为空") @RequestParam String tenantId); - - @Operation( - summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件" - ) - @PostMapping("/api/process/task/approve") - CommonResponse approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - - @Operation( - summary = "批量同意" - ) - @PostMapping("/api/process/task/batch/approve") - CommonResponse batchApproveTask( - @Validated @RequestBody List dtos); - - @Operation( - summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件" - ) - @PostMapping("/api/process/task/reject") - CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - - @PostMapping("/api/process/task/batch/reject") - CommonResponse batchRejectTask( - @Validated @RequestBody List dtos); - - @Operation( - summary = "直接修改审批任务的审批人" - ) - @PostMapping("/api/process/task/transfer") - CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); - - @Operation( - summary = "批量修改审批任务的审批人" - ) - @PostMapping("/api/process/task/batch/transfer") - CommonResponse batchTransferTask( - @Validated @RequestBody List dtos); - - @Operation( - summary = "审批流程评论" - ) - @PostMapping("/api/process/task/comment") - CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); - - @Operation( - summary = "添加附件" - ) - @PostMapping("/api/process/task/attachment") - CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); - - @Operation( - summary = "审批流程加签" - ) - @PostMapping("/api/process/task/countersign") - CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); - - @Operation( - summary = "审批流程催办" - ) - @PostMapping("/api/process/task/remind") - CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); - - @Operation( - summary = "创建机器人节点, 暂停流程任务" - ) - @PostMapping("/api/process/task/robot/create") - CommonResponse createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); - - @Operation( - summary = "完成机器人节点, 继续流程任务" - ) - @PostMapping("/api/process/task/robot/complete") - CommonResponse completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); - - @Operation( - summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID" - ) - @GetMapping("/api/process/task/find") - CommonResponse findTaskIdByInstanceIdAndPersonId( - @RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, - @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); - - @Operation( - summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID" - ) - @GetMapping("/api/process/task/batch/find") - CommonResponse> findTaskIdByInstanceIdsAndPersonId( - @RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, - @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); - - @Operation( - summary = "查询所有的审批流" - ) - @PostMapping("/api/process/instance/page/all") - CommonResponse> getAllProcessInstancePage( - @Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); - - @Operation( - summary = "我发起的审批列表" - ) - @PostMapping("/api/process/instance/page/my") - CommonResponse> getMyProcessInstancePage( - @Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); - - @Operation( - summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件" - ) - @PostMapping("/api/process/instance/create") - CommonResponse createProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCreateDTO dto); - - @Operation( - summary = "创建审批流程并带上表单" - ) - @PostMapping("/api/process/instance/form/create") - CommonResponse createProcessInstanceWith( - @Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); - - @Operation( - summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件" - ) - @DeleteMapping("/api/process/instance/cancel") - CommonResponse cancelProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCancelDTO dto); - - @Operation( - summary = "中止流程实例" - ) - @DeleteMapping("/api/process/instance/abort") - CommonResponse abortProcessInstance( - @Validated @RequestBody BpmnProcessInstanceAbortDTO dto); - - @Operation( - summary = "批量中止流程实例" - ) - @DeleteMapping("/api/process/instance/batch/abort") - CommonResponse batchAbortProcessInstance( - @Validated @RequestBody List dtos); - - @Operation( - summary = "抄送流程实例" - ) - @PostMapping("/api/process/instance/carbon-copy") - CommonResponse carbonCopyProcessInstance( - @Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); - - @Operation( - summary = "获得流程实例" - ) - @GetMapping("/api/process/instance/get") - CommonResponse getProcessInstanceVO( - @Validated @RequestBody BpmnProcessInstanceQueryDTO dto); - - @Operation( - summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例" - ) - @PutMapping("/api/process/instance/status/update") - CommonResponse updateProcessStatus( - @NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, - @NotNull(message = "状态不能为空") @RequestParam Integer status); - - @Operation( - summary = "获取审批流程实例的运行图" - ) - @GetMapping("/api/process/instance/graphical") - CommonResponse processInstanceGraphical( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - - @Operation( - summary = "推断指定流程实例的所有节点执行顺序" - ) - @GetMapping("/api/process/instance/node/forecasting") - CommonResponse> processInstanceNodeForecast( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - - @Operation( - summary = "推断指定流程实例的过滤掉部分节点执行顺序" - ) - @GetMapping("/api/process/instance/node/filter/forecasting") - CommonResponse> processInstanceFilterNodeForecast( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId, - @RequestParam(required = false, defaultValue = "false") Boolean allNode, - @Nullable @RequestParam(required = false) List nodeDefinitionKeys); - - @Operation( - summary = "获取指定流程实例的流程变量" - ) - @GetMapping("/api/process/instance/cooperation-org") - CommonResponse> getProcessVariables( - @NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - - @Operation( - summary = "查询实例的租户集合" - ) - @GetMapping("/api/process/instance/tenant/ids") - CommonResponse> getTenantIds(); - - @Operation( - summary = "校验指定流程实例下,是否存在指定的审批人" - ) - @PostMapping("/api/process/instance/check/approver") - CommonResponse checkInstanceApprover( - @Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java new file mode 100644 index 000000000..0b5f3cf5b --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -0,0 +1,26 @@ +package cn.axzo.workflow.starter.api; + +import cn.axzo.workflow.common.annotation.Manageable; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.List; + +/** + * TODO + * + * @author wangli + * @since 2024/6/11 16:32 + */ +public interface WorkflowManageService { + + /** + * 查询实例的租户集合 + * + * @return + */ + @Operation(summary = "查询实例的租户集合") + @GetMapping("/api/process/instance/tenant/ids") + @Manageable + List getTenantIds(); +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java new file mode 100644 index 000000000..64597209f --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.starter.feign.ext; + +import feign.Feign; +import feign.Target; + +/** + * TODO + * + * @author wangli + * @since 2024/6/11 15:40 + */ +public class WorkflowEngineStarterFeign { + + public static WorkflowEngineStarterFeign.Builder builder() { + return new WorkflowEngineStarterFeign.Builder(); + } + + public static final class Builder extends Feign.Builder { + + @Override + public T target(Target target) { + return super.build().newInstance(target); + } + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 980ba6d41..c04b348aa 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.azxo.framework.common.constatns.Constants; import feign.Client; +import feign.Feign; import feign.RequestInterceptor; import feign.Retryer; import feign.Target; @@ -17,6 +18,7 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; +import org.springframework.cloud.openfeign.Targeter; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; @@ -45,6 +47,16 @@ public class WorkflowEngineStarterFeignConfiguration { return new Retryer.Default(100, SECONDS.toMillis(1), 3); } + @Bean + public Feign.Builder workflowEngineStarterFeignBuilder() { + return WorkflowEngineStarterFeign.builder(); + } + + @Bean + public Targeter workflowEngineStarterFeignTargeter(WorkflowEngineStarterProperties starterProperties) { + return new WorkflowEngineStarterTargeter(starterProperties); + } + @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, @Qualifier("workflowEngineStarterEventProducer") EventProducer eventProducer, diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java new file mode 100644 index 000000000..a0e3e20b2 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java @@ -0,0 +1,27 @@ +package cn.axzo.workflow.starter.feign.ext; + +import feign.Target; + +/** + * TODO + * + * @author wangli + * @since 2024/6/11 17:00 + */ +public class WorkflowEngineStarterTarget extends Target.HardCodedTarget { + private final Class manageableInterface; + + public WorkflowEngineStarterTarget(Class type, String url, Class manageableInterface) { + super(type, url); + this.manageableInterface = manageableInterface; + } + + public WorkflowEngineStarterTarget(Class type, String name, String url, Class manageableInterface) { + super(type, name, url); + this.manageableInterface = manageableInterface; + } + + public Class getManageableInterface() { + return manageableInterface; + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java new file mode 100644 index 000000000..bfe1129e9 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.starter.feign.ext; + +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.api.WorkflowManageService; +import feign.Feign; +import feign.Target; +import org.springframework.cloud.openfeign.FeignClientFactoryBean; +import org.springframework.cloud.openfeign.FeignContext; +import org.springframework.cloud.openfeign.Targeter; + +/** + * TODO + * + * @author wangli + * @since 2024/6/11 16:12 + */ +public class WorkflowEngineStarterTargeter implements Targeter { + private final WorkflowEngineStarterProperties properties; + + public WorkflowEngineStarterTargeter(WorkflowEngineStarterProperties starterProperties) { + this.properties = starterProperties; + } + + @Override + public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { + if (!(feign instanceof WorkflowEngineStarterFeign.Builder)) { + return feign.target(target); + } + Class clazz = null; + if (properties.getManageable()) { + clazz = WorkflowManageService.class; + } + Target newTarget = new WorkflowEngineStarterTarget<>(target.type(), target.name(), target.url(), clazz); + return feign.target(newTarget); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java b/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java new file mode 100644 index 000000000..55d3e67da --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java @@ -0,0 +1,415 @@ +/** + * Copyright 2012-2020 The Feign Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package feign; + +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterTarget; +import feign.InvocationHandlerFactory.MethodHandler; +import feign.Param.Expander; +import feign.Request.Options; +import feign.codec.Decoder; +import feign.codec.EncodeException; +import feign.codec.Encoder; +import feign.codec.ErrorDecoder; +import feign.template.UriUtils; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +import static feign.Util.checkArgument; +import static feign.Util.checkNotNull; + +public class ReflectiveFeign extends Feign { + + private final ParseHandlersByName targetToHandlersByName; + private final InvocationHandlerFactory factory; + private final QueryMapEncoder queryMapEncoder; + + ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, + QueryMapEncoder queryMapEncoder) { + this.targetToHandlersByName = targetToHandlersByName; + this.factory = factory; + this.queryMapEncoder = queryMapEncoder; + } + + /** + * creates an api binding to the {@code target}. As this invokes reflection, care should be taken + * to cache the result. + */ + @SuppressWarnings("unchecked") + @Override + public T newInstance(Target target) { + Map nameToHandler = targetToHandlersByName.apply(target); + Map methodToHandler = new LinkedHashMap(); + List defaultMethodHandlers = new LinkedList(); + + for (Method method : target.type().getMethods()) { + if (method.getDeclaringClass() == Object.class) { + continue; + } else if (Util.isDefault(method)) { + DefaultMethodHandler handler = new DefaultMethodHandler(method); + defaultMethodHandlers.add(handler); + methodToHandler.put(method, handler); + } else { + methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); + } + } + InvocationHandler handler = factory.create(target, methodToHandler); + List> classList = new ArrayList<>(); + classList.add(target.type()); + if (target instanceof WorkflowEngineStarterTarget) { + Class manageableInterface = ((WorkflowEngineStarterTarget) target).getManageableInterface(); + if (Objects.nonNull(manageableInterface)) { + classList.add(manageableInterface); + } + } + T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), + classList.toArray(new Class[0]), handler); + + for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { + defaultMethodHandler.bindTo(proxy); + } + return proxy; + } + + static class FeignInvocationHandler implements InvocationHandler { + + private final Target target; + private final Map dispatch; + + FeignInvocationHandler(Target target, Map dispatch) { + this.target = checkNotNull(target, "target"); + this.dispatch = checkNotNull(dispatch, "dispatch for %s", target); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("equals".equals(method.getName())) { + try { + Object otherHandler = + args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; + return equals(otherHandler); + } catch (IllegalArgumentException e) { + return false; + } + } else if ("hashCode".equals(method.getName())) { + return hashCode(); + } else if ("toString".equals(method.getName())) { + return toString(); + } + + return dispatch.get(method).invoke(args); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FeignInvocationHandler) { + FeignInvocationHandler other = (FeignInvocationHandler) obj; + return target.equals(other.target); + } + return false; + } + + @Override + public int hashCode() { + return target.hashCode(); + } + + @Override + public String toString() { + return target.toString(); + } + } + + static final class ParseHandlersByName { + + private final Contract contract; + private final Options options; + private final Encoder encoder; + private final Decoder decoder; + private final ErrorDecoder errorDecoder; + private final QueryMapEncoder queryMapEncoder; + private final SynchronousMethodHandler.Factory factory; + + ParseHandlersByName( + Contract contract, + Options options, + Encoder encoder, + Decoder decoder, + QueryMapEncoder queryMapEncoder, + ErrorDecoder errorDecoder, + SynchronousMethodHandler.Factory factory) { + this.contract = contract; + this.options = options; + this.factory = factory; + this.errorDecoder = errorDecoder; + this.queryMapEncoder = queryMapEncoder; + this.encoder = checkNotNull(encoder, "encoder"); + this.decoder = checkNotNull(decoder, "decoder"); + } + + public Map apply(Target target) { + List metadata = contract.parseAndValidateMetadata(target.type()); + Map result = new LinkedHashMap(); + for (MethodMetadata md : metadata) { + BuildTemplateByResolvingArgs buildTemplate; + if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { + buildTemplate = + new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); + } else if (md.bodyIndex() != null) { + buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); + } else { + buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target); + } + if (md.isIgnored()) { + result.put(md.configKey(), args -> { + throw new IllegalStateException(md.configKey() + " is not a method handled by feign"); + }); + } else { + result.put(md.configKey(), + factory.create(target, md, buildTemplate, options, decoder, errorDecoder)); + } + } + return result; + } + } + + private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory { + + private final QueryMapEncoder queryMapEncoder; + + protected final MethodMetadata metadata; + protected final Target target; + private final Map indexToExpander = new LinkedHashMap(); + + private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder, + Target target) { + this.metadata = metadata; + this.target = target; + this.queryMapEncoder = queryMapEncoder; + if (metadata.indexToExpander() != null) { + indexToExpander.putAll(metadata.indexToExpander()); + return; + } + if (metadata.indexToExpanderClass().isEmpty()) { + return; + } + for (Entry> indexToExpanderClass : metadata + .indexToExpanderClass().entrySet()) { + try { + indexToExpander + .put(indexToExpanderClass.getKey(), indexToExpanderClass.getValue().newInstance()); + } catch (InstantiationException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + } + + @Override + public RequestTemplate create(Object[] argv) { + RequestTemplate mutable = RequestTemplate.from(metadata.template()); + mutable.feignTarget(target); + if (metadata.urlIndex() != null) { + int urlIndex = metadata.urlIndex(); + checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex); + mutable.target(String.valueOf(argv[urlIndex])); + } + Map varBuilder = new LinkedHashMap(); + for (Entry> entry : metadata.indexToName().entrySet()) { + int i = entry.getKey(); + Object value = argv[entry.getKey()]; + if (value != null) { // Null values are skipped. + if (indexToExpander.containsKey(i)) { + value = expandElements(indexToExpander.get(i), value); + } + for (String name : entry.getValue()) { + varBuilder.put(name, value); + } + } + } + + RequestTemplate template = resolve(argv, mutable, varBuilder); + if (metadata.queryMapIndex() != null) { + // add query map parameters after initial resolve so that they take + // precedence over any predefined values + Object value = argv[metadata.queryMapIndex()]; + Map queryMap = toQueryMap(value); + template = addQueryMapQueryParameters(queryMap, template); + } + + if (metadata.headerMapIndex() != null) { + template = + addHeaderMapHeaders((Map) argv[metadata.headerMapIndex()], template); + } + + return template; + } + + private Map toQueryMap(Object value) { + if (value instanceof Map) { + return (Map) value; + } + try { + return queryMapEncoder.encode(value); + } catch (EncodeException e) { + throw new IllegalStateException(e); + } + } + + private Object expandElements(Expander expander, Object value) { + if (value instanceof Iterable) { + return expandIterable(expander, (Iterable) value); + } + return expander.expand(value); + } + + private List expandIterable(Expander expander, Iterable value) { + List values = new ArrayList(); + for (Object element : value) { + if (element != null) { + values.add(expander.expand(element)); + } + } + return values; + } + + @SuppressWarnings("unchecked") + private RequestTemplate addHeaderMapHeaders(Map headerMap, + RequestTemplate mutable) { + for (Entry currEntry : headerMap.entrySet()) { + Collection values = new ArrayList(); + + Object currValue = currEntry.getValue(); + if (currValue instanceof Iterable) { + Iterator iter = ((Iterable) currValue).iterator(); + while (iter.hasNext()) { + Object nextObject = iter.next(); + values.add(nextObject == null ? null : nextObject.toString()); + } + } else { + values.add(currValue == null ? null : currValue.toString()); + } + + mutable.header(currEntry.getKey(), values); + } + return mutable; + } + + @SuppressWarnings("unchecked") + private RequestTemplate addQueryMapQueryParameters(Map queryMap, + RequestTemplate mutable) { + for (Entry currEntry : queryMap.entrySet()) { + Collection values = new ArrayList(); + + boolean encoded = metadata.queryMapEncoded(); + Object currValue = currEntry.getValue(); + if (currValue instanceof Iterable) { + Iterator iter = ((Iterable) currValue).iterator(); + while (iter.hasNext()) { + Object nextObject = iter.next(); + values.add(nextObject == null ? null + : encoded ? nextObject.toString() + : UriUtils.encode(nextObject.toString())); + } + } else if (currValue instanceof Object[]) { + for (Object value : (Object[]) currValue) { + values.add(value == null ? null + : encoded ? value.toString() : UriUtils.encode(value.toString())); + } + } else { + values.add(currValue == null ? null + : encoded ? currValue.toString() : UriUtils.encode(currValue.toString())); + } + + mutable.query(encoded ? currEntry.getKey() : UriUtils.encode(currEntry.getKey()), values); + } + return mutable; + } + + protected RequestTemplate resolve(Object[] argv, + RequestTemplate mutable, + Map variables) { + return mutable.resolve(variables); + } + } + + private static class BuildFormEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { + + private final Encoder encoder; + + private BuildFormEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, + QueryMapEncoder queryMapEncoder, Target target) { + super(metadata, queryMapEncoder, target); + this.encoder = encoder; + } + + @Override + protected RequestTemplate resolve(Object[] argv, + RequestTemplate mutable, + Map variables) { + Map formVariables = new LinkedHashMap(); + for (Entry entry : variables.entrySet()) { + if (metadata.formParams().contains(entry.getKey())) { + formVariables.put(entry.getKey(), entry.getValue()); + } + } + try { + encoder.encode(formVariables, Encoder.MAP_STRING_WILDCARD, mutable); + } catch (EncodeException e) { + throw e; + } catch (RuntimeException e) { + throw new EncodeException(e.getMessage(), e); + } + return super.resolve(argv, mutable, variables); + } + } + + private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { + + private final Encoder encoder; + + private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, + QueryMapEncoder queryMapEncoder, Target target) { + super(metadata, queryMapEncoder, target); + this.encoder = encoder; + } + + @Override + protected RequestTemplate resolve(Object[] argv, + RequestTemplate mutable, + Map variables) { + Object body = argv[metadata.bodyIndex()]; + checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex()); + try { + encoder.encode(body, metadata.bodyType(), mutable); + } catch (EncodeException e) { + throw e; + } catch (RuntimeException e) { + throw new EncodeException(e.getMessage(), e); + } + return super.resolve(argv, mutable, variables); + } + } +} diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java deleted file mode 100644 index 693ce34f3..000000000 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGeneration.java +++ /dev/null @@ -1,78 +0,0 @@ -package cn.axzo.workflow.support.api; - -import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.starter.WorkflowEngineStarterAutoConfiguration; -import com.github.javaparser.ParseResult; -import com.github.javaparser.ParserConfiguration; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.Modifier; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.body.Parameter; -import com.github.javaparser.ast.expr.NormalAnnotationExpr; -import com.github.javaparser.printer.DefaultPrettyPrinter; -import com.github.javaparser.printer.Printer; -import com.github.javaparser.utils.CodeGenerationUtils; -import com.github.javaparser.utils.SourceRoot; -import lombok.SneakyThrows; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; - -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -/** - * TODO - * - * @author wangli - * @since 2024/6/7 17:14 - */ -public class CodeGeneration { - - @SneakyThrows - public static void main(String[] args) { - Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineClientAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/client/feign/"); - SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); - sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); - Printer printer = new DefaultPrettyPrinter(); - sourceRoot.setPrinter(printer::print); - - List> parseResults = sourceRoot.tryToParse(); - List compilationUnits = sourceRoot.getCompilationUnits(); - compilationUnits.forEach(compilationUnit -> { -// System.out.println("compilationUnit = " + compilationUnit); - }); - - // https://www.jianshu.com/p/04b413c97988 - Path outputCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineStarterAutoConfiguration.class).resolve(Paths.get("src/main/java/cn/axzo/workflow/starter/api")); - SourceRoot outputCodeSR = new SourceRoot(outputCodeRoot); - outputCodeSR.saveAll(StandardCharsets.UTF_8); - - CompilationUnit compilationUnit = new CompilationUnit(); - ClassOrInterfaceDeclaration workflowCoreServiceTest = compilationUnit.addInterface("WorkflowCoreServiceTest").setPublic(true); - workflowCoreServiceTest.setInterface(true); - MethodDeclaration a = workflowCoreServiceTest.addMethod("a", Modifier.Keyword.PUBLIC).removeBody(); - a.setJavadocComment("创建审批流程"); - Parameter dto = a.addAndGetParameter(BpmnProcessInstanceCreateDTO.class, "dto"); - dto.addAnnotation(Validated.class).addAnnotation(RequestBody.class); - a.setType(String.class); - - NormalAnnotationExpr postMapping = a.addAndGetAnnotation(PostMapping.class); - postMapping.addPair("value", "/api/process/instance/create"); -// postMapping.setName("/api/process/instance/create"); - - NormalAnnotationExpr invokeMode = a.addAndGetAnnotation(InvokeMode.class); - invokeMode.addPair("value", "SYNC"); - -// compilationUnit.setPackageDeclaration("cn.axzo.workflow.starter.api"); - compilationUnit.addImport(BpmnProcessInstanceCreateDTO.class); - - String string = workflowCoreServiceTest.toString(); - System.out.println("string = " + string); - } -} diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java new file mode 100644 index 000000000..c56d3127b --- /dev/null +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java @@ -0,0 +1,190 @@ +package cn.axzo.workflow.support.api; + +import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.starter.WorkflowEngineStarterAutoConfiguration; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.ImportDeclaration; +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.expr.ClassExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.ast.type.Type; +import com.github.javaparser.printer.DefaultPrettyPrinter; +import com.github.javaparser.printer.Printer; +import com.github.javaparser.utils.CodeGenerationUtils; +import com.github.javaparser.utils.SourceRoot; +import lombok.SneakyThrows; +import org.springframework.cloud.openfeign.FeignClient; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; + +/** + * 生成 WorkflowCoreService 接口 + * + * @author wangli + * @since 2024/6/7 17:14 + */ +public class CoreServiceCodeGenerator { + + @SneakyThrows + public static void main(String[] args) { + String newClassName = "WorkflowCoreService"; + CompilationUnit originFile = parseOriginFile(newClassName); + + CompilationUnit testGeneric = genericCode("cn.axzo.workflow.starter.api", newClassName); + writeToStarter(testGeneric, newClassName); + + } + + @SneakyThrows + private static CompilationUnit parseOriginFile(String newClassName) { + Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineStarterAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/starter/api/"); + SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); + sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); + Printer printer = new DefaultPrettyPrinter(); + sourceRoot.setPrinter(printer::print); + sourceRoot.tryToParse(); + + List compilationUnits = sourceRoot.getCompilationUnits(); + for (CompilationUnit cu : compilationUnits) { + Optional primaryTypeName = cu.getPrimaryTypeName(); + if (primaryTypeName.isPresent() && primaryTypeName.get().equals(newClassName)) { + System.out.println("compilationUnit = " + cu); + return cu; + } + } + return null; + } + + private static void writeToStarter(CompilationUnit cu, String newClassName) { + String projectRootDir = System.getProperty("user.dir"); + String genericFilePath = Paths.get(projectRootDir, "/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/", newClassName + ".java").toString(); + try (FileWriter fileWriter = new FileWriter(genericFilePath)) { + fileWriter.append(cu.toString()); + } catch (IOException e) { + // nothing to do + } + } + + public static CompilationUnit genericCode(String pkg, String newClassName) { + CompilationUnit cu = new CompilationUnit(pkg); + ClassOrInterfaceDeclaration interfaceDeclaration = setCommon(cu, newClassName); + + addMethods(interfaceDeclaration, cu); + addDefaultMethods(interfaceDeclaration); + return cu; + } + + private static void addDefaultMethods(ClassOrInterfaceDeclaration interfaceDeclaration) { + MethodDeclaration sync = createDefaultMethod("sync", interfaceDeclaration); + sync.setJavadocComment("强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + + "

\r\n" +
+                "workflowCoreService.sync().createProcessInstance();\r\n" +
+                "
"); + + MethodDeclaration async = createDefaultMethod("async", interfaceDeclaration); + sync.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + + "
\r\n" +
+                "workflowCoreService.async().createProcessInstance();\r\n" +
+                "
"); + } + + private static MethodDeclaration createDefaultMethod(String methodName, ClassOrInterfaceDeclaration interfaceDeclaration) { + // 将sync方法添加到WorkflowCoreService类中 + MethodDeclaration methodDeclaration = interfaceDeclaration.addMethod(methodName, Modifier.Keyword.DEFAULT); + methodDeclaration.setType(new ClassOrInterfaceType("WorkflowCoreService")); + + // 创建方法体 + BlockStmt methodBody = new BlockStmt(); + + MethodCallExpr setMethodCall = new MethodCallExpr(new NameExpr("ThreadUtil"), "set"); + setMethodCall.addArgument(new NameExpr(methodName.toUpperCase())); // 使用NameExpr来表示枚举常量 + ExpressionStmt setStatement = new ExpressionStmt(setMethodCall); + + methodBody.addStatement(setStatement); + // 创建return this;的语句 + ReturnStmt returnStmt = new ReturnStmt(new ThisExpr()); + methodBody.addStatement(returnStmt); + + // 将方法体设置到sync方法中 + methodDeclaration.setBody(methodBody); + return methodDeclaration; + } + + @SneakyThrows + private static void addMethods(ClassOrInterfaceDeclaration interfaceDeclaration, CompilationUnit cu) { + Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineClientAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/client/feign/"); + SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); + sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); + Printer printer = new DefaultPrettyPrinter(); + sourceRoot.setPrinter(printer::print); + sourceRoot.tryToParse(); + + List compilationUnits = sourceRoot.getCompilationUnits(); + NodeList> targetMethods = interfaceDeclaration.getMembers(); + for (CompilationUnit apiCU : compilationUnits) { + if (!apiCU.getPrimaryType().filter(e -> e.getAnnotationByClass(Manageable.class).isPresent()).isPresent()) { + addImports(apiCU, cu); + // 类上含有 @Manageable,不进行解析 + String interfaceName = apiCU.getPrimaryTypeName().get(); + List methods = apiCU.getInterfaceByName(interfaceName).get().findAll(MethodDeclaration.class); + for (MethodDeclaration method : methods) { + if (!method.getAnnotationByClass(Manageable.class).isPresent()) { + MethodDeclaration methodDeclaration = method.clone(); + methodDeclaration.setType(changeReturnType(methodDeclaration.getType())); + targetMethods.add(methodDeclaration); + } + } + } + } + } + + private static Type changeReturnType(Type type) { + if (type instanceof ClassOrInterfaceType && type.asClassOrInterfaceType().getTypeArguments().isPresent()) { + NodeList types = type.asClassOrInterfaceType().getTypeArguments().orElse(new NodeList<>()); + if (types.size() != 1) { + throw new RuntimeException("workflow-engine-api 中的接口返回类型有误"); + } + return types.getFirst().get(); + } + return type; + } + + private static void addImports(CompilationUnit apiCU, CompilationUnit cu) { + for (ImportDeclaration sourceImport : apiCU.getImports()) { + cu.addImport(sourceImport.clone()); + } + } + + private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { + ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); + classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service"); + classOrInterfaceDeclaration.addAndGetAnnotation(FeignClient.class) + .addPair("name", new StringLiteralExpr("workflow-engine-starter")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) + .addPair("configuration", new ClassExpr(new ClassOrInterfaceType(null, WorkflowEngineStarterFeignConfiguration.class.getSimpleName()))); + cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); + cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); + cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC", true, false); + cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC", true, false); + return classOrInterfaceDeclaration; + } +} diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java new file mode 100644 index 000000000..00fb79bcb --- /dev/null +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java @@ -0,0 +1,166 @@ +package cn.axzo.workflow.support.api; + +import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.ImportDeclaration; +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.expr.ClassExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.ast.type.Type; +import com.github.javaparser.printer.DefaultPrettyPrinter; +import com.github.javaparser.printer.Printer; +import com.github.javaparser.utils.CodeGenerationUtils; +import com.github.javaparser.utils.SourceRoot; +import lombok.SneakyThrows; +import org.springframework.cloud.openfeign.FeignClient; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * 生成 WorkflowManageService 接口 + * + * @author wangli + * @since 2024/6/11 17:38 + */ +public class ManageServiceCodeGenerator { + @SneakyThrows + public static void main(String[] args) { + String newClassName = "WorkflowManageService"; + + CompilationUnit testGeneric = genericCode("cn.axzo.workflow.starter.api", newClassName); + writeToStarter(testGeneric, newClassName); + + } + + private static void writeToStarter(CompilationUnit cu, String newClassName) { + String projectRootDir = System.getProperty("user.dir"); + String genericFilePath = Paths.get(projectRootDir, "/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/", newClassName + ".java").toString(); + try (FileWriter fileWriter = new FileWriter(genericFilePath)) { + fileWriter.append(cu.toString()); + } catch (IOException e) { + // nothing to do + } + } + + public static CompilationUnit genericCode(String pkg, String newClassName) { + CompilationUnit cu = new CompilationUnit(pkg); + ClassOrInterfaceDeclaration interfaceDeclaration = setCommon(cu, newClassName); + + addMethods(interfaceDeclaration, cu); + addDefaultMethods(interfaceDeclaration); + return cu; + } + + private static void addDefaultMethods(ClassOrInterfaceDeclaration interfaceDeclaration) { + MethodDeclaration sync = createDefaultMethod("sync", interfaceDeclaration); + sync.setJavadocComment("强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + + "
\r\n" +
+                "workflowCoreService.sync().createProcessInstance();\r\n" +
+                "
"); + + MethodDeclaration async = createDefaultMethod("async", interfaceDeclaration); + sync.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + + "
\r\n" +
+                "workflowCoreService.async().createProcessInstance();\r\n" +
+                "
"); + } + + private static MethodDeclaration createDefaultMethod(String methodName, ClassOrInterfaceDeclaration interfaceDeclaration) { + // 将sync方法添加到WorkflowCoreService类中 + MethodDeclaration methodDeclaration = interfaceDeclaration.addMethod(methodName, Modifier.Keyword.DEFAULT); + methodDeclaration.setType(new ClassOrInterfaceType("WorkflowCoreService")); + + // 创建方法体 + BlockStmt methodBody = new BlockStmt(); + + MethodCallExpr setMethodCall = new MethodCallExpr(new NameExpr("ThreadUtil"), "set"); + setMethodCall.addArgument(new NameExpr(methodName.toUpperCase())); // 使用NameExpr来表示枚举常量 + ExpressionStmt setStatement = new ExpressionStmt(setMethodCall); + + methodBody.addStatement(setStatement); + // 创建return this;的语句 + ReturnStmt returnStmt = new ReturnStmt(new ThisExpr()); + methodBody.addStatement(returnStmt); + + // 将方法体设置到sync方法中 + methodDeclaration.setBody(methodBody); + return methodDeclaration; + } + + @SneakyThrows + private static void addMethods(ClassOrInterfaceDeclaration interfaceDeclaration, CompilationUnit cu) { + Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineClientAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/client/feign/"); + SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); + sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); + Printer printer = new DefaultPrettyPrinter(); + sourceRoot.setPrinter(printer::print); + sourceRoot.tryToParse(); + + List compilationUnits = sourceRoot.getCompilationUnits(); + NodeList> targetMethods = interfaceDeclaration.getMembers(); + for (CompilationUnit apiCU : compilationUnits) { + if (!apiCU.getPrimaryType().filter(e -> e.getAnnotationByClass(Manageable.class).isPresent()).isPresent()) { + addImports(apiCU, cu); + // 类上含有 @Manageable,不进行解析 + String interfaceName = apiCU.getPrimaryTypeName().get(); + List methods = apiCU.getInterfaceByName(interfaceName).get().findAll(MethodDeclaration.class); + for (MethodDeclaration method : methods) { + if (!method.getAnnotationByClass(Manageable.class).isPresent()) { + MethodDeclaration methodDeclaration = method.clone(); + methodDeclaration.setType(changeReturnType(methodDeclaration.getType())); + targetMethods.add(methodDeclaration); + } + } + } + } + } + + private static Type changeReturnType(Type type) { + if (type instanceof ClassOrInterfaceType && type.asClassOrInterfaceType().getTypeArguments().isPresent()) { + NodeList types = type.asClassOrInterfaceType().getTypeArguments().orElse(new NodeList<>()); + if (types.size() != 1) { + throw new RuntimeException("workflow-engine-api 中的接口返回类型有误"); + } + return types.getFirst().get(); + } + return type; + } + + private static void addImports(CompilationUnit apiCU, CompilationUnit cu) { + for (ImportDeclaration sourceImport : apiCU.getImports()) { + cu.addImport(sourceImport.clone()); + } + } + + private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { + ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); + classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service"); + classOrInterfaceDeclaration.addAndGetAnnotation(FeignClient.class) + .addPair("name", new StringLiteralExpr("workflow-engine-starter")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) + .addPair("configuration", new ClassExpr(new ClassOrInterfaceType(null, WorkflowEngineStarterFeignConfiguration.class.getSimpleName()))); + cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); + cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); + cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC", true, false); + cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC", true, false); + return classOrInterfaceDeclaration; + } +} From 1de79ba629d09a20b37db4d417195f2ac78a9d90 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 11 Jun 2024 18:41:01 +0800 Subject: [PATCH 087/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=9A=82?= =?UTF-8?q?=E6=97=B6=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 12 ++++++++++-- .../WorkflowEngineStarterAutoConfiguration.java | 5 +++-- .../starter/api/WorkflowManageService.java | 17 ++++++++++++++++- .../feign/ext/WorkflowEngineStarterDecoder.java | 6 +++++- .../retry/producer/RpcInvokeEventProducer.java | 3 ++- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 50cd4e9ba..512a8cb6b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -13,7 +13,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; -import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.azxo.framework.common.model.CommonResponse; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; @@ -68,7 +68,8 @@ public class TestController { @Autowired private BpmnProcessInstanceService bpmnProcessInstanceService; @Autowired - private WorkflowCoreService workflowCoreService; +// private WorkflowCoreService workflowCoreService; + private WorkflowManageService workflowCoreService; @RepeatSubmit @GetMapping("/test") @@ -242,4 +243,11 @@ public class TestController { workflowCoreService.batchAbortProcessInstance(dtos); return CommonResponse.success(dtos); } + + @GetMapping("/tenant/get/ids") + public CommonResponse> test11() { + workflowCoreService.sync(); + List tenantIds = workflowCoreService.getTenantIds(); + return CommonResponse.success(tenantIds); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 1a5a1d190..92d0ea378 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.starter; -import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.handler.MessageNotificationEventHandler; import cn.axzo.workflow.starter.handler.ProcessActivityEventHandler; @@ -49,7 +49,8 @@ import java.util.List; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) -@EnableFeignClients(clients = {WorkflowCoreService.class}) +//@EnableFeignClients(clients = {WorkflowCoreService.class}) +@EnableFeignClients(clients = {WorkflowManageService.class}) @Import({StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class}) public class WorkflowEngineStarterAutoConfiguration { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 0b5f3cf5b..3d02b7683 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,7 +1,9 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import java.util.List; @@ -12,7 +14,8 @@ import java.util.List; * @author wangli * @since 2024/6/11 16:32 */ -public interface WorkflowManageService { +@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +public interface WorkflowManageService extends WorkflowCoreService { /** * 查询实例的租户集合 @@ -23,4 +26,16 @@ public interface WorkflowManageService { @GetMapping("/api/process/instance/tenant/ids") @Manageable List getTenantIds(); + +// @Override +// default WorkflowManageService sync() { +// ThreadUtil.set(SYNC); +// return this; +// } + +// @Override +// default WorkflowManageService async() { +// ThreadUtil.set(ASYNC); +// return this; +// } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index c2f920b23..4dae9b073 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.feign.ext; import cn.azxo.framework.common.model.CommonResponse; +import com.google.common.collect.Lists; import feign.Response; import feign.Util; import feign.codec.Decoder; @@ -11,6 +12,8 @@ import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -58,7 +61,8 @@ final class WorkflowEngineStarterDecoder implements Decoder { */ Object convert(Response response, Type type) throws IOException { ParameterizedTypeImpl wrappedType; - if (type instanceof ParameterizedType) { + List> cls = Lists.newArrayList(List.class, Map.class); + if (type instanceof ParameterizedType && !cls.contains(((ParameterizedType) type).getRawType())) { wrappedType = (ParameterizedTypeImpl) type; } else { wrappedType = ParameterizedTypeImpl.make(CommonResponse.class, new Type[]{type}, null); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index a28fc4e61..8851fb25d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -10,6 +10,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import lombok.NonNull; +import org.apache.commons.collections4.ListUtils; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -100,7 +101,7 @@ public class RpcInvokeEventProducer extends RocketMQEventProducer { getAfterCommitExecutor().executeAndRollback(runnable, rollbackRunnable); } - List runnables = getAfterCommitExecutor().getRunnables(); + List runnables = ListUtils.emptyIfNull(getAfterCommitExecutor().getRunnables()); log.info("runnables.size(): {}", runnables.size()); } From a26d1321be2e25f8c5f4254d15aa0423c6c35b59 Mon Sep 17 00:00:00 2001 From: wangli Date: Tue, 11 Jun 2024 22:14:38 +0800 Subject: [PATCH 088/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=94=AF=E6=8C=81=20properties=20=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=20manageable=20=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/TestController.java | 11 +- .../StarterFeignClientConfiguration.java | 31 + .../StarterRPCInvokeMQConfiguration.java | 9 +- ...orkflowEngineStarterAutoConfiguration.java | 6 +- .../starter/api/WorkflowManageService.java | 261 +++++- .../feign/ext/WorkflowEngineStarterFeign.java | 50 +- ...rkflowEngineStarterFeignConfiguration.java | 18 +- .../ext/WorkflowEngineStarterTarget.java | 54 +- .../ext/WorkflowEngineStarterTargeter.java | 72 +- ...rkflowEngineStarterRetryEventListener.java | 46 +- .../src/main/java/feign/ReflectiveFeign.java | 830 +++++++++--------- 11 files changed, 847 insertions(+), 541 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index 512a8cb6b..a15efae9b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -13,7 +13,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; -import cn.axzo.workflow.starter.api.WorkflowManageService; +import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.azxo.framework.common.model.CommonResponse; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; @@ -68,8 +68,9 @@ public class TestController { @Autowired private BpmnProcessInstanceService bpmnProcessInstanceService; @Autowired -// private WorkflowCoreService workflowCoreService; - private WorkflowManageService workflowCoreService; + private WorkflowCoreService workflowCoreService; +// @Autowired +// private WorkflowManageService workflowCoreService; @RepeatSubmit @GetMapping("/test") @@ -247,7 +248,7 @@ public class TestController { @GetMapping("/tenant/get/ids") public CommonResponse> test11() { workflowCoreService.sync(); - List tenantIds = workflowCoreService.getTenantIds(); - return CommonResponse.success(tenantIds); +// List tenantIds = workflowCoreService.getTenantIds(); + return CommonResponse.success(); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java new file mode 100644 index 000000000..5343fc609 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java @@ -0,0 +1,31 @@ +package cn.axzo.workflow.starter; + +import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.api.WorkflowManageService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; + +/** + * TODO + * + * @author wangli + * @since 2024/6/11 21:26 + */ +@Configuration(proxyBeanMethods = false) +public class StarterFeignClientConfiguration { + + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "manageable", havingValue = "true", matchIfMissing = true) + @EnableFeignClients(clients = WorkflowCoreService.class) + public static class WorkflowCoreServiceClient { + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "manageable", havingValue = "false") + @EnableFeignClients(clients = WorkflowManageService.class) + public static class WorkflowManageServiceClient { + + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 57edb2a74..34aee44a6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -9,6 +9,7 @@ import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; @@ -22,6 +23,7 @@ import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -192,8 +194,11 @@ public class StarterRPCInvokeMQConfiguration { @Bean public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier("workflowEngineStarterEventConsumer") EventConsumer workflowEngineStarterEventConsumer, Environment environment, - WorkflowCoreService workflowCoreService) { - return new WorkflowEngineStarterRetryEventListener(workflowEngineStarterEventConsumer, environment, workflowCoreService); + WorkflowEngineStarterProperties starterProperties, + ObjectProvider workflowCoreServiceObjectProvider, + ObjectProvider workflowManageServiceObjectProvider) { + return new WorkflowEngineStarterRetryEventListener(workflowEngineStarterEventConsumer, environment, starterProperties, + workflowCoreServiceObjectProvider, workflowManageServiceObjectProvider); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 92d0ea378..8ac831880 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.starter; -import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; import cn.axzo.workflow.starter.handler.MessageNotificationEventHandler; import cn.axzo.workflow.starter.handler.ProcessActivityEventHandler; @@ -33,7 +32,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -50,8 +48,8 @@ import java.util.List; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) //@EnableFeignClients(clients = {WorkflowCoreService.class}) -@EnableFeignClients(clients = {WorkflowManageService.class}) -@Import({StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class}) +//@EnableFeignClients(clients = {WorkflowManageService.class}) +@Import({StarterFeignClientConfiguration.class, StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class}) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 3d02b7683..66086355c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,12 +1,39 @@ package cn.axzo.workflow.starter.api; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import javax.annotation.Nullable; +import javax.validation.constraints.NotBlank; import java.util.List; +import java.util.Map; + +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; /** * TODO @@ -15,8 +42,222 @@ import java.util.List; * @since 2024/6/11 16:32 */ @FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) -public interface WorkflowManageService extends WorkflowCoreService { +public interface WorkflowManageService { + /** + * 业务节点唤醒 + *

+ * TODO 接口需要合并,但需要考虑客户端与服务端不同版本间如何兼容 + */ + @GetMapping("/api/process/activity/old/trigger") + Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); + + @Operation(summary = "业务节点唤醒") + @GetMapping("/api/process/activity/trigger") + Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, @RequestParam(required = false, defaultValue = "false") Boolean async); + + /** + * 业务节点设置审批人, 不支持重复设置 + * + * @param dto + * @return + */ + @PostMapping("/api/process/activity/assignee/set") + @Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人") + Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto); + + /** + * 创建审批流程 + * + *

+     *   MQ 触发规则:
+     *     1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
+     *     2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
+     * 
+ * + * @param dto {@link BpmnProcessInstanceCreateDTO} + */ + @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") + @PostMapping("/api/process/instance/create") + @InvokeMode(SYNC) + String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + + /** + * 发起人主动撤回审核 + * + *
+     *   MQ 触发规则:
+     *     1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
+     *     2. 当前流程实例会触发 process-instance-cancelled 事件
+     * 
+ * + * @param dto {@link BpmnProcessInstanceCancelDTO} + * @return + */ + @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件") + @DeleteMapping("/api/process/instance/cancel") + Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto); + + /** + * 中止流程实例 + * + * @param dto + * @return + */ + @Operation(summary = "中止流程实例") + @DeleteMapping("/api/process/instance/abort") + Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto); + + /** + * 批量中止流程实例 + * + * @param dtos + * @return + */ + @Operation(summary = "批量中止流程实例") + @DeleteMapping("/api/process/instance/batch/abort") + BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); + + /** + * 抄送流程实例 + * + * @param dto + * @return + */ + @Operation(summary = "抄送流程实例") + @PostMapping("/api/process/instance/carbon-copy") + Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); + + /** + * 获得流程实例 + * + * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询 + * @return 流程实例, 租户Id不必传 + */ + @Operation(summary = "获得流程实例") + @GetMapping("/api/process/instance/get") + BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + + /** + * 获取指定流程实例的流程变量 + * + * @param processInstanceId + * @param tenantId + * @return + */ + @Operation(summary = "获取指定流程实例的流程变量") + @GetMapping("/api/process/instance/cooperation-org") + Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + @GetMapping("/api/process/job/dead-letter/resume") + Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + + /** + * 同意 + * + *
+     * MQ 触发规则:
+     *  1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
+     *  如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
+     *  2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
+     *  2.2. 流程实例正常结束会触发 process-instance-completed 事件
+     * 
+ */ + @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") + @PostMapping("/api/process/task/approve") + Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + /** + * 批量同意 + * + * @param dtos + * @return + */ + @Operation(summary = "批量同意") + @PostMapping("/api/process/task/batch/approve") + BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); + + /** + * 驳回 + * + *
+     * MQ 触发规则:
+     *   1. 当前审批任务会触发 process-task-deleted 事件
+     *   2. 当前流程实例会触发 process-instance-rejected 事件
+     * 
+ */ + @Operation(summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件") + @PostMapping("/api/process/task/reject") + Boolean rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + /** + * 批量驳回 + * + * @param dtos 批量请求参数 + * @return + */ + @PostMapping("/api/process/task/batch/reject") + BatchOperationResultVO batchRejectTask(@Validated @RequestBody List dtos); + + /** + * 转交 + * + * @param dto + * @return + */ + @Operation(summary = "直接修改审批任务的审批人") + @PostMapping("/api/process/task/transfer") + Boolean transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); + + /** + * 批量转交 + * + * @param dtos + * @return + */ + @Operation(summary = "批量修改审批任务的审批人") + @PostMapping("/api/process/task/batch/transfer") + BatchOperationResultVO batchTransferTask(@Validated @RequestBody List dtos); + + /** + * 评论 + * + * @param dto 评论请求参数 + * @return + */ + @Operation(summary = "审批流程评论") + @PostMapping("/api/process/task/comment") + Boolean commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); + + /** + * 加签 + * + * @param dto 加签请求参数 + * @return + */ + @Operation(summary = "审批流程加签") + @PostMapping("/api/process/task/countersign") + Boolean countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); + + /** + * 暂停流程任务,并创建机器人节点,等待业务推动 + * + * @param dto + * @return 返回机器人节点任务 ID + */ + @Operation(summary = "创建机器人节点, 暂停流程任务") + @PostMapping("/api/process/task/robot/create") + String createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); + + /** + * 完成机器人节点 + * + * @param dto + * @return + */ + @Operation(summary = "完成机器人节点, 继续流程任务") + @PostMapping("/api/process/task/robot/complete") + Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); /** * 查询实例的租户集合 * @@ -27,15 +268,13 @@ public interface WorkflowManageService extends WorkflowCoreService { @Manageable List getTenantIds(); -// @Override -// default WorkflowManageService sync() { -// ThreadUtil.set(SYNC); -// return this; -// } + default WorkflowManageService sync() { + ThreadUtil.set(SYNC); + return this; + } -// @Override -// default WorkflowManageService async() { -// ThreadUtil.set(ASYNC); -// return this; -// } + default WorkflowManageService async() { + ThreadUtil.set(ASYNC); + return this; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java index 64597209f..3e2676a47 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java @@ -1,25 +1,25 @@ -package cn.axzo.workflow.starter.feign.ext; - -import feign.Feign; -import feign.Target; - -/** - * TODO - * - * @author wangli - * @since 2024/6/11 15:40 - */ -public class WorkflowEngineStarterFeign { - - public static WorkflowEngineStarterFeign.Builder builder() { - return new WorkflowEngineStarterFeign.Builder(); - } - - public static final class Builder extends Feign.Builder { - - @Override - public T target(Target target) { - return super.build().newInstance(target); - } - } -} +//package cn.axzo.workflow.starter.feign.ext; +// +//import feign.Feign; +//import feign.Target; +// +///** +// * TODO +// * +// * @author wangli +// * @since 2024/6/11 15:40 +// */ +//public class WorkflowEngineStarterFeign { +// +// public static WorkflowEngineStarterFeign.Builder builder() { +// return new WorkflowEngineStarterFeign.Builder(); +// } +// +// public static final class Builder extends Feign.Builder { +// +// @Override +// public T target(Target target) { +// return super.build().newInstance(target); +// } +// } +//} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index c04b348aa..d16bc7f37 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -6,7 +6,6 @@ import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.azxo.framework.common.constatns.Constants; import feign.Client; -import feign.Feign; import feign.RequestInterceptor; import feign.Retryer; import feign.Target; @@ -18,7 +17,6 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; -import org.springframework.cloud.openfeign.Targeter; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; @@ -47,15 +45,15 @@ public class WorkflowEngineStarterFeignConfiguration { return new Retryer.Default(100, SECONDS.toMillis(1), 3); } - @Bean - public Feign.Builder workflowEngineStarterFeignBuilder() { - return WorkflowEngineStarterFeign.builder(); - } +// @Bean +// public Feign.Builder workflowEngineStarterFeignBuilder() { +// return WorkflowEngineStarterFeign.builder(); +// } - @Bean - public Targeter workflowEngineStarterFeignTargeter(WorkflowEngineStarterProperties starterProperties) { - return new WorkflowEngineStarterTargeter(starterProperties); - } +// @Bean +// public Targeter workflowEngineStarterFeignTargeter(WorkflowEngineStarterProperties starterProperties) { +// return new WorkflowEngineStarterTargeter(starterProperties); +// } @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java index a0e3e20b2..909c14041 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java @@ -1,27 +1,27 @@ -package cn.axzo.workflow.starter.feign.ext; - -import feign.Target; - -/** - * TODO - * - * @author wangli - * @since 2024/6/11 17:00 - */ -public class WorkflowEngineStarterTarget extends Target.HardCodedTarget { - private final Class manageableInterface; - - public WorkflowEngineStarterTarget(Class type, String url, Class manageableInterface) { - super(type, url); - this.manageableInterface = manageableInterface; - } - - public WorkflowEngineStarterTarget(Class type, String name, String url, Class manageableInterface) { - super(type, name, url); - this.manageableInterface = manageableInterface; - } - - public Class getManageableInterface() { - return manageableInterface; - } -} +//package cn.axzo.workflow.starter.feign.ext; +// +//import feign.Target; +// +///** +// * TODO +// * +// * @author wangli +// * @since 2024/6/11 17:00 +// */ +//public class WorkflowEngineStarterTarget extends Target.HardCodedTarget { +// private final Class manageableInterface; +// +// public WorkflowEngineStarterTarget(Class type, String url, Class manageableInterface) { +// super(type, url); +// this.manageableInterface = manageableInterface; +// } +// +// public WorkflowEngineStarterTarget(Class type, String name, String url, Class manageableInterface) { +// super(type, name, url); +// this.manageableInterface = manageableInterface; +// } +// +// public Class getManageableInterface() { +// return manageableInterface; +// } +//} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java index bfe1129e9..9fe61c5e9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java @@ -1,36 +1,36 @@ -package cn.axzo.workflow.starter.feign.ext; - -import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.api.WorkflowManageService; -import feign.Feign; -import feign.Target; -import org.springframework.cloud.openfeign.FeignClientFactoryBean; -import org.springframework.cloud.openfeign.FeignContext; -import org.springframework.cloud.openfeign.Targeter; - -/** - * TODO - * - * @author wangli - * @since 2024/6/11 16:12 - */ -public class WorkflowEngineStarterTargeter implements Targeter { - private final WorkflowEngineStarterProperties properties; - - public WorkflowEngineStarterTargeter(WorkflowEngineStarterProperties starterProperties) { - this.properties = starterProperties; - } - - @Override - public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { - if (!(feign instanceof WorkflowEngineStarterFeign.Builder)) { - return feign.target(target); - } - Class clazz = null; - if (properties.getManageable()) { - clazz = WorkflowManageService.class; - } - Target newTarget = new WorkflowEngineStarterTarget<>(target.type(), target.name(), target.url(), clazz); - return feign.target(newTarget); - } -} +//package cn.axzo.workflow.starter.feign.ext; +// +//import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +//import cn.axzo.workflow.starter.api.WorkflowManageService; +//import feign.Feign; +//import feign.Target; +//import org.springframework.cloud.openfeign.FeignClientFactoryBean; +//import org.springframework.cloud.openfeign.FeignContext; +//import org.springframework.cloud.openfeign.Targeter; +// +///** +// * TODO +// * +// * @author wangli +// * @since 2024/6/11 16:12 +// */ +//public class WorkflowEngineStarterTargeter implements Targeter { +// private final WorkflowEngineStarterProperties properties; +// +// public WorkflowEngineStarterTargeter(WorkflowEngineStarterProperties starterProperties) { +// this.properties = starterProperties; +// } +// +// @Override +// public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { +// if (!(feign instanceof WorkflowEngineStarterFeign.Builder)) { +// return feign.target(target); +// } +// Class clazz = null; +// if (properties.getManageable()) { +// clazz = WorkflowManageService.class; +// } +// Target newTarget = new WorkflowEngineStarterTarget<>(target.type(), target.name(), target.url(), clazz); +// return feign.target(newTarget); +// } +//} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index da8689e1e..1eac34b65 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -6,12 +6,15 @@ import cn.axzo.framework.rocketmq.EventHandler; import cn.axzo.workflow.common.enums.WorkflowEngineEventEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.common.util.ThreadUtil; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.api.WorkflowManageService; import com.alibaba.fastjson.JSON; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; @@ -40,27 +43,53 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryEventListener.class); private final EventConsumer workflowEngineStarterEventConsumer; private final Environment environment; + private final WorkflowEngineStarterProperties starterProperties; private final String currentApplicationName; - private final WorkflowCoreService workflowCoreService; + private WorkflowCoreService workflowCoreService; + private WorkflowManageService workflowManageService; private final Map methodCache = new HashMap<>(); public WorkflowEngineStarterRetryEventListener(EventConsumer workflowEngineStarterEventConsumer, Environment environment, - WorkflowCoreService workflowCoreService) { + WorkflowEngineStarterProperties starterProperties, + ObjectProvider workflowCoreServiceObjectProvider, + ObjectProvider workflowManageServiceObjectProvider) { this.workflowEngineStarterEventConsumer = workflowEngineStarterEventConsumer; this.environment = environment; + this.starterProperties = starterProperties; this.currentApplicationName = environment.getProperty("spring.application.name"); - this.workflowCoreService = workflowCoreService; - parseWorkflowCoreService(); + workflowCoreServiceObjectProvider.ifAvailable(core -> { + this.workflowCoreService = core; + parseWorkflowCoreService(); + }); + workflowManageServiceObjectProvider.ifAvailable(manage -> { + this.workflowManageService = manage; + parseWorkflowManageService(); + }); } + private void parseWorkflowCoreService() { Class coreService = (Class) workflowCoreService.getClass().getGenericInterfaces()[0]; FeignClient feignClient = AnnotationUtils.findAnnotation(coreService, FeignClient.class); if (Objects.isNull(feignClient)) { throw new IllegalStateException("WorkflowCoreService 配置错误,没有找到 FeignClient 注解"); } - String parsedFeignContextUrl = resolveExpression(feignClient.url()); +// String parsedFeignContextUrl = resolveExpression(feignClient.url()); + + Method[] methods = coreService.getDeclaredMethods(); + for (Method method : methods) { + methodCache.put(method.getName(), method); + } + } + + private void parseWorkflowManageService() { + Class coreService = (Class) workflowManageService.getClass().getGenericInterfaces()[0]; + FeignClient feignClient = AnnotationUtils.findAnnotation(coreService, FeignClient.class); + if (Objects.isNull(feignClient)) { + throw new IllegalStateException("WorkflowCoreService 配置错误,没有找到 FeignClient 注解"); + } +// String parsedFeignContextUrl = resolveExpression(feignClient.url()); Method[] methods = coreService.getDeclaredMethods(); for (Method method : methods) { @@ -97,7 +126,12 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In ThreadUtil.set(SYNC); Object[] args = convertToActualArgs(method, dto.getParameters()); log.info("event rpc request args: {}", JSON.toJSONString(args)); - Object invoke = method.invoke(workflowCoreService, args); + Object invoke; + if (starterProperties.getManageable()) { + invoke = method.invoke(workflowCoreService, args); + } else { + invoke = method.invoke(workflowManageService, args); + } log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 diff --git a/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java b/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java index 55d3e67da..fa6f83310 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java +++ b/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java @@ -1,415 +1,415 @@ -/** - * Copyright 2012-2020 The Feign Authors - *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package feign; - -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterTarget; -import feign.InvocationHandlerFactory.MethodHandler; -import feign.Param.Expander; -import feign.Request.Options; -import feign.codec.Decoder; -import feign.codec.EncodeException; -import feign.codec.Encoder; -import feign.codec.ErrorDecoder; -import feign.template.UriUtils; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -import static feign.Util.checkArgument; -import static feign.Util.checkNotNull; - -public class ReflectiveFeign extends Feign { - - private final ParseHandlersByName targetToHandlersByName; - private final InvocationHandlerFactory factory; - private final QueryMapEncoder queryMapEncoder; - - ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, - QueryMapEncoder queryMapEncoder) { - this.targetToHandlersByName = targetToHandlersByName; - this.factory = factory; - this.queryMapEncoder = queryMapEncoder; - } - - /** - * creates an api binding to the {@code target}. As this invokes reflection, care should be taken - * to cache the result. - */ - @SuppressWarnings("unchecked") - @Override - public T newInstance(Target target) { - Map nameToHandler = targetToHandlersByName.apply(target); - Map methodToHandler = new LinkedHashMap(); - List defaultMethodHandlers = new LinkedList(); - - for (Method method : target.type().getMethods()) { - if (method.getDeclaringClass() == Object.class) { - continue; - } else if (Util.isDefault(method)) { - DefaultMethodHandler handler = new DefaultMethodHandler(method); - defaultMethodHandlers.add(handler); - methodToHandler.put(method, handler); - } else { - methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); - } - } - InvocationHandler handler = factory.create(target, methodToHandler); - List> classList = new ArrayList<>(); - classList.add(target.type()); - if (target instanceof WorkflowEngineStarterTarget) { - Class manageableInterface = ((WorkflowEngineStarterTarget) target).getManageableInterface(); - if (Objects.nonNull(manageableInterface)) { - classList.add(manageableInterface); - } - } - T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), - classList.toArray(new Class[0]), handler); - - for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { - defaultMethodHandler.bindTo(proxy); - } - return proxy; - } - - static class FeignInvocationHandler implements InvocationHandler { - - private final Target target; - private final Map dispatch; - - FeignInvocationHandler(Target target, Map dispatch) { - this.target = checkNotNull(target, "target"); - this.dispatch = checkNotNull(dispatch, "dispatch for %s", target); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if ("equals".equals(method.getName())) { - try { - Object otherHandler = - args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; - return equals(otherHandler); - } catch (IllegalArgumentException e) { - return false; - } - } else if ("hashCode".equals(method.getName())) { - return hashCode(); - } else if ("toString".equals(method.getName())) { - return toString(); - } - - return dispatch.get(method).invoke(args); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof FeignInvocationHandler) { - FeignInvocationHandler other = (FeignInvocationHandler) obj; - return target.equals(other.target); - } - return false; - } - - @Override - public int hashCode() { - return target.hashCode(); - } - - @Override - public String toString() { - return target.toString(); - } - } - - static final class ParseHandlersByName { - - private final Contract contract; - private final Options options; - private final Encoder encoder; - private final Decoder decoder; - private final ErrorDecoder errorDecoder; - private final QueryMapEncoder queryMapEncoder; - private final SynchronousMethodHandler.Factory factory; - - ParseHandlersByName( - Contract contract, - Options options, - Encoder encoder, - Decoder decoder, - QueryMapEncoder queryMapEncoder, - ErrorDecoder errorDecoder, - SynchronousMethodHandler.Factory factory) { - this.contract = contract; - this.options = options; - this.factory = factory; - this.errorDecoder = errorDecoder; - this.queryMapEncoder = queryMapEncoder; - this.encoder = checkNotNull(encoder, "encoder"); - this.decoder = checkNotNull(decoder, "decoder"); - } - - public Map apply(Target target) { - List metadata = contract.parseAndValidateMetadata(target.type()); - Map result = new LinkedHashMap(); - for (MethodMetadata md : metadata) { - BuildTemplateByResolvingArgs buildTemplate; - if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { - buildTemplate = - new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); - } else if (md.bodyIndex() != null) { - buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); - } else { - buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target); - } - if (md.isIgnored()) { - result.put(md.configKey(), args -> { - throw new IllegalStateException(md.configKey() + " is not a method handled by feign"); - }); - } else { - result.put(md.configKey(), - factory.create(target, md, buildTemplate, options, decoder, errorDecoder)); - } - } - return result; - } - } - - private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory { - - private final QueryMapEncoder queryMapEncoder; - - protected final MethodMetadata metadata; - protected final Target target; - private final Map indexToExpander = new LinkedHashMap(); - - private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder, - Target target) { - this.metadata = metadata; - this.target = target; - this.queryMapEncoder = queryMapEncoder; - if (metadata.indexToExpander() != null) { - indexToExpander.putAll(metadata.indexToExpander()); - return; - } - if (metadata.indexToExpanderClass().isEmpty()) { - return; - } - for (Entry> indexToExpanderClass : metadata - .indexToExpanderClass().entrySet()) { - try { - indexToExpander - .put(indexToExpanderClass.getKey(), indexToExpanderClass.getValue().newInstance()); - } catch (InstantiationException e) { - throw new IllegalStateException(e); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - } - - @Override - public RequestTemplate create(Object[] argv) { - RequestTemplate mutable = RequestTemplate.from(metadata.template()); - mutable.feignTarget(target); - if (metadata.urlIndex() != null) { - int urlIndex = metadata.urlIndex(); - checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex); - mutable.target(String.valueOf(argv[urlIndex])); - } - Map varBuilder = new LinkedHashMap(); - for (Entry> entry : metadata.indexToName().entrySet()) { - int i = entry.getKey(); - Object value = argv[entry.getKey()]; - if (value != null) { // Null values are skipped. - if (indexToExpander.containsKey(i)) { - value = expandElements(indexToExpander.get(i), value); - } - for (String name : entry.getValue()) { - varBuilder.put(name, value); - } - } - } - - RequestTemplate template = resolve(argv, mutable, varBuilder); - if (metadata.queryMapIndex() != null) { - // add query map parameters after initial resolve so that they take - // precedence over any predefined values - Object value = argv[metadata.queryMapIndex()]; - Map queryMap = toQueryMap(value); - template = addQueryMapQueryParameters(queryMap, template); - } - - if (metadata.headerMapIndex() != null) { - template = - addHeaderMapHeaders((Map) argv[metadata.headerMapIndex()], template); - } - - return template; - } - - private Map toQueryMap(Object value) { - if (value instanceof Map) { - return (Map) value; - } - try { - return queryMapEncoder.encode(value); - } catch (EncodeException e) { - throw new IllegalStateException(e); - } - } - - private Object expandElements(Expander expander, Object value) { - if (value instanceof Iterable) { - return expandIterable(expander, (Iterable) value); - } - return expander.expand(value); - } - - private List expandIterable(Expander expander, Iterable value) { - List values = new ArrayList(); - for (Object element : value) { - if (element != null) { - values.add(expander.expand(element)); - } - } - return values; - } - - @SuppressWarnings("unchecked") - private RequestTemplate addHeaderMapHeaders(Map headerMap, - RequestTemplate mutable) { - for (Entry currEntry : headerMap.entrySet()) { - Collection values = new ArrayList(); - - Object currValue = currEntry.getValue(); - if (currValue instanceof Iterable) { - Iterator iter = ((Iterable) currValue).iterator(); - while (iter.hasNext()) { - Object nextObject = iter.next(); - values.add(nextObject == null ? null : nextObject.toString()); - } - } else { - values.add(currValue == null ? null : currValue.toString()); - } - - mutable.header(currEntry.getKey(), values); - } - return mutable; - } - - @SuppressWarnings("unchecked") - private RequestTemplate addQueryMapQueryParameters(Map queryMap, - RequestTemplate mutable) { - for (Entry currEntry : queryMap.entrySet()) { - Collection values = new ArrayList(); - - boolean encoded = metadata.queryMapEncoded(); - Object currValue = currEntry.getValue(); - if (currValue instanceof Iterable) { - Iterator iter = ((Iterable) currValue).iterator(); - while (iter.hasNext()) { - Object nextObject = iter.next(); - values.add(nextObject == null ? null - : encoded ? nextObject.toString() - : UriUtils.encode(nextObject.toString())); - } - } else if (currValue instanceof Object[]) { - for (Object value : (Object[]) currValue) { - values.add(value == null ? null - : encoded ? value.toString() : UriUtils.encode(value.toString())); - } - } else { - values.add(currValue == null ? null - : encoded ? currValue.toString() : UriUtils.encode(currValue.toString())); - } - - mutable.query(encoded ? currEntry.getKey() : UriUtils.encode(currEntry.getKey()), values); - } - return mutable; - } - - protected RequestTemplate resolve(Object[] argv, - RequestTemplate mutable, - Map variables) { - return mutable.resolve(variables); - } - } - - private static class BuildFormEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { - - private final Encoder encoder; - - private BuildFormEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, - QueryMapEncoder queryMapEncoder, Target target) { - super(metadata, queryMapEncoder, target); - this.encoder = encoder; - } - - @Override - protected RequestTemplate resolve(Object[] argv, - RequestTemplate mutable, - Map variables) { - Map formVariables = new LinkedHashMap(); - for (Entry entry : variables.entrySet()) { - if (metadata.formParams().contains(entry.getKey())) { - formVariables.put(entry.getKey(), entry.getValue()); - } - } - try { - encoder.encode(formVariables, Encoder.MAP_STRING_WILDCARD, mutable); - } catch (EncodeException e) { - throw e; - } catch (RuntimeException e) { - throw new EncodeException(e.getMessage(), e); - } - return super.resolve(argv, mutable, variables); - } - } - - private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { - - private final Encoder encoder; - - private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, - QueryMapEncoder queryMapEncoder, Target target) { - super(metadata, queryMapEncoder, target); - this.encoder = encoder; - } - - @Override - protected RequestTemplate resolve(Object[] argv, - RequestTemplate mutable, - Map variables) { - Object body = argv[metadata.bodyIndex()]; - checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex()); - try { - encoder.encode(body, metadata.bodyType(), mutable); - } catch (EncodeException e) { - throw e; - } catch (RuntimeException e) { - throw new EncodeException(e.getMessage(), e); - } - return super.resolve(argv, mutable, variables); - } - } -} +///** +// * Copyright 2012-2020 The Feign Authors +// *

+// * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// * in compliance with the License. You may obtain a copy of the License at +// *

+// * http://www.apache.org/licenses/LICENSE-2.0 +// *

+// * Unless required by applicable law or agreed to in writing, software distributed under the License +// * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +// * or implied. See the License for the specific language governing permissions and limitations under +// * the License. +// */ +//package feign; +// +//import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterTarget; +//import feign.InvocationHandlerFactory.MethodHandler; +//import feign.Param.Expander; +//import feign.Request.Options; +//import feign.codec.Decoder; +//import feign.codec.EncodeException; +//import feign.codec.Encoder; +//import feign.codec.ErrorDecoder; +//import feign.template.UriUtils; +// +//import java.lang.reflect.InvocationHandler; +//import java.lang.reflect.Method; +//import java.lang.reflect.Proxy; +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.Iterator; +//import java.util.LinkedHashMap; +//import java.util.LinkedList; +//import java.util.List; +//import java.util.Map; +//import java.util.Map.Entry; +//import java.util.Objects; +// +//import static feign.Util.checkArgument; +//import static feign.Util.checkNotNull; +// +//public class ReflectiveFeign extends Feign { +// +// private final ParseHandlersByName targetToHandlersByName; +// private final InvocationHandlerFactory factory; +// private final QueryMapEncoder queryMapEncoder; +// +// ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, +// QueryMapEncoder queryMapEncoder) { +// this.targetToHandlersByName = targetToHandlersByName; +// this.factory = factory; +// this.queryMapEncoder = queryMapEncoder; +// } +// +// /** +// * creates an api binding to the {@code target}. As this invokes reflection, care should be taken +// * to cache the result. +// */ +// @SuppressWarnings("unchecked") +// @Override +// public T newInstance(Target target) { +// Map nameToHandler = targetToHandlersByName.apply(target); +// Map methodToHandler = new LinkedHashMap(); +// List defaultMethodHandlers = new LinkedList(); +// +// for (Method method : target.type().getMethods()) { +// if (method.getDeclaringClass() == Object.class) { +// continue; +// } else if (Util.isDefault(method)) { +// DefaultMethodHandler handler = new DefaultMethodHandler(method); +// defaultMethodHandlers.add(handler); +// methodToHandler.put(method, handler); +// } else { +// methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); +// } +// } +// InvocationHandler handler = factory.create(target, methodToHandler); +// List> classList = new ArrayList<>(); +// classList.add(target.type()); +// if (target instanceof WorkflowEngineStarterTarget) { +// Class manageableInterface = ((WorkflowEngineStarterTarget) target).getManageableInterface(); +// if (Objects.nonNull(manageableInterface)) { +// classList.add(manageableInterface); +// } +// } +// T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), +// classList.toArray(new Class[0]), handler); +// +// for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { +// defaultMethodHandler.bindTo(proxy); +// } +// return proxy; +// } +// +// static class FeignInvocationHandler implements InvocationHandler { +// +// private final Target target; +// private final Map dispatch; +// +// FeignInvocationHandler(Target target, Map dispatch) { +// this.target = checkNotNull(target, "target"); +// this.dispatch = checkNotNull(dispatch, "dispatch for %s", target); +// } +// +// @Override +// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { +// if ("equals".equals(method.getName())) { +// try { +// Object otherHandler = +// args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; +// return equals(otherHandler); +// } catch (IllegalArgumentException e) { +// return false; +// } +// } else if ("hashCode".equals(method.getName())) { +// return hashCode(); +// } else if ("toString".equals(method.getName())) { +// return toString(); +// } +// +// return dispatch.get(method).invoke(args); +// } +// +// @Override +// public boolean equals(Object obj) { +// if (obj instanceof FeignInvocationHandler) { +// FeignInvocationHandler other = (FeignInvocationHandler) obj; +// return target.equals(other.target); +// } +// return false; +// } +// +// @Override +// public int hashCode() { +// return target.hashCode(); +// } +// +// @Override +// public String toString() { +// return target.toString(); +// } +// } +// +// static final class ParseHandlersByName { +// +// private final Contract contract; +// private final Options options; +// private final Encoder encoder; +// private final Decoder decoder; +// private final ErrorDecoder errorDecoder; +// private final QueryMapEncoder queryMapEncoder; +// private final SynchronousMethodHandler.Factory factory; +// +// ParseHandlersByName( +// Contract contract, +// Options options, +// Encoder encoder, +// Decoder decoder, +// QueryMapEncoder queryMapEncoder, +// ErrorDecoder errorDecoder, +// SynchronousMethodHandler.Factory factory) { +// this.contract = contract; +// this.options = options; +// this.factory = factory; +// this.errorDecoder = errorDecoder; +// this.queryMapEncoder = queryMapEncoder; +// this.encoder = checkNotNull(encoder, "encoder"); +// this.decoder = checkNotNull(decoder, "decoder"); +// } +// +// public Map apply(Target target) { +// List metadata = contract.parseAndValidateMetadata(target.type()); +// Map result = new LinkedHashMap(); +// for (MethodMetadata md : metadata) { +// BuildTemplateByResolvingArgs buildTemplate; +// if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { +// buildTemplate = +// new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); +// } else if (md.bodyIndex() != null) { +// buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); +// } else { +// buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target); +// } +// if (md.isIgnored()) { +// result.put(md.configKey(), args -> { +// throw new IllegalStateException(md.configKey() + " is not a method handled by feign"); +// }); +// } else { +// result.put(md.configKey(), +// factory.create(target, md, buildTemplate, options, decoder, errorDecoder)); +// } +// } +// return result; +// } +// } +// +// private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory { +// +// private final QueryMapEncoder queryMapEncoder; +// +// protected final MethodMetadata metadata; +// protected final Target target; +// private final Map indexToExpander = new LinkedHashMap(); +// +// private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder, +// Target target) { +// this.metadata = metadata; +// this.target = target; +// this.queryMapEncoder = queryMapEncoder; +// if (metadata.indexToExpander() != null) { +// indexToExpander.putAll(metadata.indexToExpander()); +// return; +// } +// if (metadata.indexToExpanderClass().isEmpty()) { +// return; +// } +// for (Entry> indexToExpanderClass : metadata +// .indexToExpanderClass().entrySet()) { +// try { +// indexToExpander +// .put(indexToExpanderClass.getKey(), indexToExpanderClass.getValue().newInstance()); +// } catch (InstantiationException e) { +// throw new IllegalStateException(e); +// } catch (IllegalAccessException e) { +// throw new IllegalStateException(e); +// } +// } +// } +// +// @Override +// public RequestTemplate create(Object[] argv) { +// RequestTemplate mutable = RequestTemplate.from(metadata.template()); +// mutable.feignTarget(target); +// if (metadata.urlIndex() != null) { +// int urlIndex = metadata.urlIndex(); +// checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex); +// mutable.target(String.valueOf(argv[urlIndex])); +// } +// Map varBuilder = new LinkedHashMap(); +// for (Entry> entry : metadata.indexToName().entrySet()) { +// int i = entry.getKey(); +// Object value = argv[entry.getKey()]; +// if (value != null) { // Null values are skipped. +// if (indexToExpander.containsKey(i)) { +// value = expandElements(indexToExpander.get(i), value); +// } +// for (String name : entry.getValue()) { +// varBuilder.put(name, value); +// } +// } +// } +// +// RequestTemplate template = resolve(argv, mutable, varBuilder); +// if (metadata.queryMapIndex() != null) { +// // add query map parameters after initial resolve so that they take +// // precedence over any predefined values +// Object value = argv[metadata.queryMapIndex()]; +// Map queryMap = toQueryMap(value); +// template = addQueryMapQueryParameters(queryMap, template); +// } +// +// if (metadata.headerMapIndex() != null) { +// template = +// addHeaderMapHeaders((Map) argv[metadata.headerMapIndex()], template); +// } +// +// return template; +// } +// +// private Map toQueryMap(Object value) { +// if (value instanceof Map) { +// return (Map) value; +// } +// try { +// return queryMapEncoder.encode(value); +// } catch (EncodeException e) { +// throw new IllegalStateException(e); +// } +// } +// +// private Object expandElements(Expander expander, Object value) { +// if (value instanceof Iterable) { +// return expandIterable(expander, (Iterable) value); +// } +// return expander.expand(value); +// } +// +// private List expandIterable(Expander expander, Iterable value) { +// List values = new ArrayList(); +// for (Object element : value) { +// if (element != null) { +// values.add(expander.expand(element)); +// } +// } +// return values; +// } +// +// @SuppressWarnings("unchecked") +// private RequestTemplate addHeaderMapHeaders(Map headerMap, +// RequestTemplate mutable) { +// for (Entry currEntry : headerMap.entrySet()) { +// Collection values = new ArrayList(); +// +// Object currValue = currEntry.getValue(); +// if (currValue instanceof Iterable) { +// Iterator iter = ((Iterable) currValue).iterator(); +// while (iter.hasNext()) { +// Object nextObject = iter.next(); +// values.add(nextObject == null ? null : nextObject.toString()); +// } +// } else { +// values.add(currValue == null ? null : currValue.toString()); +// } +// +// mutable.header(currEntry.getKey(), values); +// } +// return mutable; +// } +// +// @SuppressWarnings("unchecked") +// private RequestTemplate addQueryMapQueryParameters(Map queryMap, +// RequestTemplate mutable) { +// for (Entry currEntry : queryMap.entrySet()) { +// Collection values = new ArrayList(); +// +// boolean encoded = metadata.queryMapEncoded(); +// Object currValue = currEntry.getValue(); +// if (currValue instanceof Iterable) { +// Iterator iter = ((Iterable) currValue).iterator(); +// while (iter.hasNext()) { +// Object nextObject = iter.next(); +// values.add(nextObject == null ? null +// : encoded ? nextObject.toString() +// : UriUtils.encode(nextObject.toString())); +// } +// } else if (currValue instanceof Object[]) { +// for (Object value : (Object[]) currValue) { +// values.add(value == null ? null +// : encoded ? value.toString() : UriUtils.encode(value.toString())); +// } +// } else { +// values.add(currValue == null ? null +// : encoded ? currValue.toString() : UriUtils.encode(currValue.toString())); +// } +// +// mutable.query(encoded ? currEntry.getKey() : UriUtils.encode(currEntry.getKey()), values); +// } +// return mutable; +// } +// +// protected RequestTemplate resolve(Object[] argv, +// RequestTemplate mutable, +// Map variables) { +// return mutable.resolve(variables); +// } +// } +// +// private static class BuildFormEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { +// +// private final Encoder encoder; +// +// private BuildFormEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, +// QueryMapEncoder queryMapEncoder, Target target) { +// super(metadata, queryMapEncoder, target); +// this.encoder = encoder; +// } +// +// @Override +// protected RequestTemplate resolve(Object[] argv, +// RequestTemplate mutable, +// Map variables) { +// Map formVariables = new LinkedHashMap(); +// for (Entry entry : variables.entrySet()) { +// if (metadata.formParams().contains(entry.getKey())) { +// formVariables.put(entry.getKey(), entry.getValue()); +// } +// } +// try { +// encoder.encode(formVariables, Encoder.MAP_STRING_WILDCARD, mutable); +// } catch (EncodeException e) { +// throw e; +// } catch (RuntimeException e) { +// throw new EncodeException(e.getMessage(), e); +// } +// return super.resolve(argv, mutable, variables); +// } +// } +// +// private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { +// +// private final Encoder encoder; +// +// private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, +// QueryMapEncoder queryMapEncoder, Target target) { +// super(metadata, queryMapEncoder, target); +// this.encoder = encoder; +// } +// +// @Override +// protected RequestTemplate resolve(Object[] argv, +// RequestTemplate mutable, +// Map variables) { +// Object body = argv[metadata.bodyIndex()]; +// checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex()); +// try { +// encoder.encode(body, metadata.bodyType(), mutable); +// } catch (EncodeException e) { +// throw e; +// } catch (RuntimeException e) { +// throw new EncodeException(e.getMessage(), e); +// } +// return super.resolve(argv, mutable, variables); +// } +// } +//} From 997773182dbc688676e5df0c2de06019268e98e9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 10:08:42 +0800 Subject: [PATCH 089/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20maven=20=E8=87=AA=E5=8A=A8=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=94=9F=E6=88=90=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowManageService.java | 802 +++++++++++++----- 1 file changed, 584 insertions(+), 218 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 66086355c..f2cd19cb3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,263 +1,305 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.util.ThreadUtil; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import io.swagger.v3.oas.annotations.Operation; +import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.annotation.Nullable; -import javax.validation.constraints.NotBlank; -import java.util.List; -import java.util.Map; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.axzo.workflow.common.util.ThreadUtil; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; +import cn.azxo.framework.common.model.CommonResponse; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.List; + +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import javax.annotation.Nullable; +import java.util.Map; + +import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; +import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; +import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; +import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; +import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; +import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; +import org.springframework.web.bind.annotation.PathVariable; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; + +import javax.validation.constraints.NotEmpty; + +import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; + /** - * TODO - * - * @author wangli - * @since 2024/6/11 16:32 + * Workflow Engine Starter Management Service */ -@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { /** - * 业务节点唤醒 + * 获取流程操作按钮列表 + * + * @return 流程操作按钮列表 + */ + @GetMapping("/api/process/config/button/list") + List getDefaultButtons(); + + /** + * 流程模型列表 + * + * @param dto + * @return + */ + @Operation(summary = "流程模型列表") + @GetMapping("/api/process/model/page") + BpmPageResult page(@Validated @RequestBody BpmnModelSearchDTO dto); + + /** + * 创建流程, + * return modelId的主键 + */ + @Operation(summary = "创建流程模型") + @PostMapping("/api/process/model/create") + String create(@Validated @RequestBody BpmnModelCreateDTO dto); + + /** + * 通过模型 ID 获取模型 + */ + @Operation(summary = "通过模型ID查询指定流程模型") + @GetMapping("/api/process/model/get") + BpmnModelDetailVO getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false) String tenantId); + + /** + * 通过模型 KEY 获取模型 + */ + @Operation(summary = "通过模型KEY查询指定流程模型") + @GetMapping("/api/process/model/getByKey") + BpmnModelDetailVO getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId); + + /** + * 校验是否能更新模型即其关联的流程定义内容 *

- * TODO 接口需要合并,但需要考虑客户端与服务端不同版本间如何兼容 + * 偏向业务的接口,flowable 引擎是站在流程定义维度进行激活和挂起 + * + * @return true 能更新,表明该模型关联的所有定义版本都是挂起状态 */ - @GetMapping("/api/process/activity/old/trigger") - Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); - - @Operation(summary = "业务节点唤醒") - @GetMapping("/api/process/activity/trigger") - Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, @RequestParam(required = false, defaultValue = "false") Boolean async); + @Operation(summary = "获取指定模型的扩展属性") + @GetMapping("/api/process/model/ext") + BpmnModelExtVO getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId); /** - * 业务节点设置审批人, 不支持重复设置 + * 修改流程信息 + */ + @Operation(summary = "更新流程模型") + @PutMapping("/api/process/model/update") + String update(@RequestBody BpmnModelUpdateDTO dto); + + /** + * 通过模型 ID 部署模型 + * + * @return 部署完成的流程定义Id + */ + @Operation(summary = "通过模型 ID 部署流程模型") + @PostMapping("/api/process/model/deploy") + String deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String modelTenantId, @RequestParam(required = false) String operator); + + /** + * 通过模型 KEY 部署模型 + * + * @return 部署完成的流程定义Id + */ + @Operation(summary = "通过模型 KEY 部署流程模型") + @PostMapping("/api/process/model/deployByKey") + String deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId, @RequestParam(required = false) String operator); + + /** + * 通过模型 ID 取消部署流程模型 + * + * @param processModelId + * @param tenantId + * @param operator + * @return + */ + @Operation(summary = "通过模型 ID 取消部署流程模型") + @PostMapping("/api/process/model/undeploy") + Void unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId, @RequestParam(required = false) String operator); + + /** + * 通过模型 ID 删除模型 + */ + @Operation(summary = "删除指定模型 ID 的流程模型") + @DeleteMapping("/api/process/model/delete") + Void deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId); + + /** + * 通过模型 KEY 删除模型 + * + * @param processModelKey + * @param tenantId + * @return + */ + @Operation(summary = "删除指定模型 KEY 的流程模型") + @DeleteMapping("/api/process/model/deleteByKey") + Void deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey, @RequestParam(required = false, defaultValue = "") String tenantId); + + /** + * 通过模型 ID 修改模型状态 + * + * @param modelId + * @param status + * @param operator + * @return + */ + @Operation(summary = "修改模型状态") + @PostMapping("/api/process/model/changeStatus") + Void changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId, @NotNull(message = "状态不能为空") @RequestParam Integer status, @RequestParam(required = false) String operator); + + /** + * 查询流程模型使用的分类列表 + * + * @return + */ + @Operation(summary = "查询流程模型使用的分类列表") + @GetMapping("/api/process/model/category/ids") + List getModelCategoryList(); + + /** + * 查询模型的租户集合 + * + * @return + */ + @Operation(summary = "查询模型的租户集合") + @GetMapping("/api/process/model/tenant/ids") + List getModelTenantIds(); + + /** + * 查询所有的审批流 + * + * @return + */ + @Operation(summary = "查询所有的审批流") + @PostMapping("/api/process/instance/page/all") + @Manageable + BpmPageResult getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); + + /** + * 我发起的审批列表 + */ + @Operation(summary = "我发起的审批列表") + @PostMapping("/api/process/instance/page/my") + @Manageable + BpmPageResult getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); + + /** + * 创建审批流程并带上表单 * * @param dto * @return */ - @PostMapping("/api/process/activity/assignee/set") - @Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人") - Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto); + @Operation(summary = "创建审批流程并带上表单") + @PostMapping("/api/process/instance/form/create") + @Manageable + String createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); /** - * 创建审批流程 + * 更新流程定义的状态 * - *

-     *   MQ 触发规则:
-     *     1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
-     *     2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
-     * 
- * - * @param dto {@link BpmnProcessInstanceCreateDTO} + * @param processDefinitionId 流程定义的编号 + * @param status 1, "active"; 2, "suspended" */ - @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") - @PostMapping("/api/process/instance/create") - @InvokeMode(SYNC) - String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例") + @PutMapping("/api/process/instance/status/update") + @Manageable + Boolean updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status); /** - * 发起人主动撤回审核 - * - *
-     *   MQ 触发规则:
-     *     1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
-     *     2. 当前流程实例会触发 process-instance-cancelled 事件
-     * 
- * - * @param dto {@link BpmnProcessInstanceCancelDTO} - * @return - */ - @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件") - @DeleteMapping("/api/process/instance/cancel") - Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto); - - /** - * 中止流程实例 - * - * @param dto - * @return - */ - @Operation(summary = "中止流程实例") - @DeleteMapping("/api/process/instance/abort") - Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto); - - /** - * 批量中止流程实例 - * - * @param dtos - * @return - */ - @Operation(summary = "批量中止流程实例") - @DeleteMapping("/api/process/instance/batch/abort") - BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); - - /** - * 抄送流程实例 - * - * @param dto - * @return - */ - @Operation(summary = "抄送流程实例") - @PostMapping("/api/process/instance/carbon-copy") - Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); - - /** - * 获得流程实例 - * - * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询 - * @return 流程实例, 租户Id不必传 - */ - @Operation(summary = "获得流程实例") - @GetMapping("/api/process/instance/get") - BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); - - /** - * 获取指定流程实例的流程变量 + * 获取审批流程实例的运行图 * * @param processInstanceId * @param tenantId * @return */ - @Operation(summary = "获取指定流程实例的流程变量") - @GetMapping("/api/process/instance/cooperation-org") - Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - @GetMapping("/api/process/job/dead-letter/resume") - Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + @Operation(summary = "获取审批流程实例的运行图") + @GetMapping("/api/process/instance/graphical") + @Manageable + ObjectNode processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** - * 同意 + * 推断指定流程实例的所有节点执行顺序 * - *
-     * MQ 触发规则:
-     *  1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
-     *  如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
-     *  2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
-     *  2.2. 流程实例正常结束会触发 process-instance-completed 事件
-     * 
- */ - @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") - @PostMapping("/api/process/task/approve") - Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - - /** - * 批量同意 - * - * @param dtos * @return */ - @Operation(summary = "批量同意") - @PostMapping("/api/process/task/batch/approve") - BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); + @Operation(summary = "推断指定流程实例的所有节点执行顺序") + @GetMapping("/api/process/instance/node/forecasting") + @Manageable + List processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** - * 驳回 + * 推断指定流程实例的过滤掉部分节点执行顺序 * - *
-     * MQ 触发规则:
-     *   1. 当前审批任务会触发 process-task-deleted 事件
-     *   2. 当前流程实例会触发 process-instance-rejected 事件
-     * 
- */ - @Operation(summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件") - @PostMapping("/api/process/task/reject") - Boolean rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - - /** - * 批量驳回 - * - * @param dtos 批量请求参数 + * @param allNode 如果为真时,相当于调用 {@link ProcessInstanceApi#processInstanceNodeForecast(String, String)} 方法,切会直接丢弃 nodeDefinitionKeys 参数 + * 如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点 * @return */ - @PostMapping("/api/process/task/batch/reject") - BatchOperationResultVO batchRejectTask(@Validated @RequestBody List dtos); + @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") + @GetMapping("/api/process/instance/node/filter/forecasting") + @Manageable + List processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @Nullable @RequestParam(required = false) List nodeDefinitionKeys); - /** - * 转交 - * - * @param dto - * @return - */ - @Operation(summary = "直接修改审批任务的审批人") - @PostMapping("/api/process/task/transfer") - Boolean transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); - - /** - * 批量转交 - * - * @param dtos - * @return - */ - @Operation(summary = "批量修改审批任务的审批人") - @PostMapping("/api/process/task/batch/transfer") - BatchOperationResultVO batchTransferTask(@Validated @RequestBody List dtos); - - /** - * 评论 - * - * @param dto 评论请求参数 - * @return - */ - @Operation(summary = "审批流程评论") - @PostMapping("/api/process/task/comment") - Boolean commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); - - /** - * 加签 - * - * @param dto 加签请求参数 - * @return - */ - @Operation(summary = "审批流程加签") - @PostMapping("/api/process/task/countersign") - Boolean countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); - - /** - * 暂停流程任务,并创建机器人节点,等待业务推动 - * - * @param dto - * @return 返回机器人节点任务 ID - */ - @Operation(summary = "创建机器人节点, 暂停流程任务") - @PostMapping("/api/process/task/robot/create") - String createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); - - /** - * 完成机器人节点 - * - * @param dto - * @return - */ - @Operation(summary = "完成机器人节点, 继续流程任务") - @PostMapping("/api/process/task/robot/complete") - Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); /** * 查询实例的租户集合 * @@ -268,6 +310,330 @@ public interface WorkflowManageService { @Manageable List getTenantIds(); + /** + * 校验指定流程实例下,是否存在指定的审批人 + * + * @return true 是在当前流程实例中,存在指定的审批人 + */ + @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") + @PostMapping("/api/process/instance/check/approver") + @Manageable + Boolean checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); + + /** + * 获取指定业务分类 + * + * @return + */ + @GetMapping("/api/process/category/get") + CategoryItemVO get(@RequestParam Long id); + + /** + * 获取指定业务分类集合 + * + * @param ids + * @return + */ + @GetMapping("/api/process/category/getByIds") + List getByIds(@RequestParam List ids); + + /** + * 获取指定业务分类集合 + * + * @param values + * @return + */ + @GetMapping("/api/process/category/getByValues") + List getByValues(@RequestParam List values); + + /** + * 新增业务分类 + * + * @return + */ + @PostMapping("/api/process/category/create") + CategoryItemVO create(@Validated @RequestBody CategoryCreateDTO req); + + /** + * 更新业务分类 + * + * @return + */ + @PutMapping("/api/process/category/update") + CategoryItemVO update(@Validated @RequestBody CategoryUpdateDTO dto); + + /** + * 删除指定业务分类 + * + * @param id + * @return + */ + @DeleteMapping("/api/process/category/delete") + Boolean delete(@RequestParam Long id); + + /** + * 更新指定分类状态 + * + * @param id + * @param state + * @return + */ + @PutMapping("/api/process/category/update/state") + Boolean updateState(@RequestParam Long id, @RequestParam Boolean state); + + /** + * 获取指定业务分类集合 + * + * @return + */ + @PostMapping("/api/process/category/list") + List list(@RequestBody CategorySearchDTO dto); + + /** + * 搜索业务分类 + * + * @return + */ + @PostMapping("/api/process/category/page/search") + BpmPageResult search(@RequestBody CategorySearchDTO dto); + + /** + * 业务分类创建黑白名单配置项 + * + * @param dto + * @return + */ + @PostMapping("/api/process/category/config/create") + Boolean createConfig(@RequestBody CategoryConfigCreateDTO dto); + + /** + * 删除指定分类的配置项数据 + * + * @param id + * @return + */ + @DeleteMapping("/api/process/category/config/delete/{id}") + Boolean deleteConfig(@PathVariable Long id); + + /** + * 业务分类黑白名单查询 + * + * @return + */ + @PostMapping("/api/process/category/config/page/search") + BpmPageResult configSearch(@RequestBody CategoryConfigSearchDTO dto); + + /** + * 更新业务分类的配置类型 + * + * @param id + * @param configType + * @return + */ + @PostMapping("/api/process/category/config/type/update") + Boolean updateCategoryConfigType(@RequestParam Long id, @RequestParam String configType); + + /** + * 用于业务方判断指定的业务分类的黑白名单配置 + * + * @param tenantId 租户ID + * @param categoryCode 业务分类编码 + * @return true: 可以发起创建流程实例, false: 不可用 + */ + @GetMapping("/api/process/category/check/status") + Boolean checkCategoryStatus(@RequestParam Long tenantId, @RequestParam String categoryCode); + + /** + * 为指定流程新增变量 + */ + @PostMapping("/api/process/variable/create/{executionId}") + Void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); + + /** + * 仅更新流程已存在的变量 + * + * @param executionId + * @param restVariable + * @return + */ + @PostMapping("/api/process/variable/update/{executionId}") + Void updateVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); + + /** + * 批量删除流程变量 + */ + @DeleteMapping("/api/process/variable/delete/{executionId}") + Void deleteVariables(@PathVariable("executionId") String executionId, @RequestParam String variableNames, @RequestParam(value = "scope", required = false) String scope); + + /** + * 待审核列表 + */ + @Operation(summary = "待审核列表") + @GetMapping("/api/process/task/page/todo") + @Manageable + BpmPageResult getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); + + /** + * 已完成的审批列表 + */ + @Operation(summary = "已完成的审批列表") + @GetMapping("/api/process/task/page/done") + @Manageable + BpmPageResult getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); + + /** + * 获取指定流程实例的审批过程信息 + *

+ * 同一层级结构 + */ + @Operation(summary = "获取指定流程实例的审批过程信息") + @GetMapping("/api/process/task/list/flat") + @Manageable + List getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取指定流程实例的审批过程信息 + *

+ * 分组结构 + */ + @Operation(summary = "获取指定流程实例的审批过程信息") + @GetMapping("/api/process/task/list/group") + @Manageable + List getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取实例正在审核的人列表 + */ + @Operation(summary = "获取实例正在审核的人列表") + @GetMapping("/api/process/task/active/list") + @Manageable + List getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + + /** + * 添加附件 + * + * @param dto + * @return + */ + @Operation(summary = "添加附件") + @PostMapping("/api/process/task/attachment") + @Manageable + Void addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); + + /** + * 催办 + * + * @param dto + * @return + */ + @Operation(summary = "审批流程催办") + @PostMapping("/api/process/task/remind") + @Manageable + Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); + + /** + * 根据实例 ID 和自然人 ID 查询对应待处理的任务 ID + * + * @return + */ + @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") + @GetMapping("/api/process/task/find") + @Manageable + String findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + + /** + * 根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID + * + * @return + */ + @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") + @GetMapping("/api/process/task/batch/find") + @Manageable + Map findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + + /** + * 获取活跃的流程定义分页 + */ + @GetMapping("/api/process/definition/page") + BpmPageResult getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto); + + /** + * 通过模型 ID 更新流程定义 + * + * @param dto + * @return + */ + @PutMapping("/api/process/definition/update") + Boolean updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto); + + /** + * 获得指定定义编号对应的流程定义内容 + * + * @param processDefinitionId 编号 + * @return 流程定义 + */ + @GetMapping("/api/process/definition/get") + BpmnProcessDefinitionVO getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId); + + /** + * 获得 deploymentId 对应的 ProcessDefinition + * + * @param deploymentId 部署编号 + * @return 流程定义 + */ + @GetMapping("/api/process/definition/getByDeploymentId") + BpmnProcessDefinitionVO getProcessDefinitionByDeploymentId(@NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId); + + /** + * 获得流程定义标识对应的激活的流程定义 + * + * @param key 流程定义的标识 + * @return 流程定义 + */ + @GetMapping("/api/process/definition/active/getByKey") + BpmnProcessDefinitionVO getActiveProcessDefinitionByKey(@NotBlank(message = "模型定义KEY不能为空") @RequestParam String key); + + /** + * 挂起/激活流程, + * 激活:SuspensionState.ACTIVE.getStateCode() + * 挂起:SuspensionState.SUSPENDED.getStateCode() + * {@see SuspensionState} + */ + @PutMapping("/api/process/definition/state/update") + Boolean getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer state); + + /** + * 获取指定模型的定义 ID + * + * @return 流程定义ID + */ + @GetMapping("/api/process/definition/active/getByCategory") + String getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category); + + /** + * 获取指定模型激活的流程定义 JSON 模型 + * + * @return 流程定义ID + */ + @GetMapping("/api/process/definition/active/json/model") + BpmnModelUpdateDTO getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category, @RequestParam(required = false) String tenantId); + + /** + * 删除流程部署及定义 + * + * @param deploymentId 流程定义部署 ID + * @param cascade 是否级联参数定义对应的流程实例及 job 等管理内容 + * @return + */ + @GetMapping("/api/process/definition/delete") + Void delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId, @RequestParam(required = false) Boolean cascade); + + /** + * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 + *

+     *   workflowManageService.async().getTenantIds();
+     * 
+ */ default WorkflowManageService sync() { ThreadUtil.set(SYNC); return this; From 386cbf9597e0b4c8a478e3d18f3e9457fcf32cbf Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 11:05:40 +0800 Subject: [PATCH 090/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20Javaparser=20=E7=94=9F=E6=88=90=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C=E5=B9=B6=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=20Maven=20=E5=9C=A8=E6=89=93=E5=8C=85=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E8=83=BD=E8=87=AA=E5=8A=A8=E5=85=88=E7=94=9F=E6=88=90=EF=BC=8C?= =?UTF-8?q?=E5=86=8D=20package=20starter=20=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../client/feign/bpmn/ProcessModelApi.java | 2 +- .../server/controller/web/TestController.java | 10 +-- .../web/bpmn/BpmnProcessModelController.java | 2 +- .../StarterFeignClientConfiguration.java | 7 +- workflow-engine-support/pom.xml | 29 ++++++-- .../workflow/support/api/CodeGenerator.java | 17 +++++ ...or.java => CoreServiceCodeGeneration.java} | 43 +++++------- ....java => ManageServiceCodeGeneration.java} | 66 ++++++++++--------- 9 files changed, 105 insertions(+), 73 deletions(-) create mode 100644 workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGenerator.java rename workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/{CoreServiceCodeGenerator.java => CoreServiceCodeGeneration.java} (83%) rename workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/{ManageServiceCodeGenerator.java => ManageServiceCodeGeneration.java} (73%) diff --git a/pom.xml b/pom.xml index 2947d97f2..5ebad126a 100644 --- a/pom.xml +++ b/pom.xml @@ -159,7 +159,7 @@ workflow-engine-common workflow-engine-core workflow-engine-server - workflow-engine-spring-boot-starter workflow-engine-support + workflow-engine-spring-boot-starter diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index 0da4f77d0..f3eca0f22 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -172,5 +172,5 @@ public interface ProcessModelApi { */ @Operation(summary = "查询模型的租户集合") @GetMapping("/api/process/model/tenant/ids") - CommonResponse> getTenantIds(); + CommonResponse> getModelTenantIds(); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index a15efae9b..f8e0c34e7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -14,6 +14,7 @@ import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; import cn.axzo.workflow.starter.api.WorkflowCoreService; +import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.azxo.framework.common.model.CommonResponse; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; @@ -69,8 +70,8 @@ public class TestController { private BpmnProcessInstanceService bpmnProcessInstanceService; @Autowired private WorkflowCoreService workflowCoreService; -// @Autowired -// private WorkflowManageService workflowCoreService; + @Autowired + private WorkflowManageService workflowManageService; @RepeatSubmit @GetMapping("/test") @@ -247,8 +248,7 @@ public class TestController { @GetMapping("/tenant/get/ids") public CommonResponse> test11() { - workflowCoreService.sync(); -// List tenantIds = workflowCoreService.getTenantIds(); - return CommonResponse.success(); + List tenantIds = workflowManageService.sync().getTenantIds(); + return CommonResponse.success(tenantIds); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java index 9d92c3dc7..2924e846b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessModelController.java @@ -274,7 +274,7 @@ public class BpmnProcessModelController implements ProcessModelApi { @Operation(summary = "查询模型的租户集合") @GetMapping("/tenant/ids") @Override - public CommonResponse> getTenantIds() { + public CommonResponse> getModelTenantIds() { log.info("查询模型的租户集合getTenantIds"); return success(bpmnProcessModelService.getTenantIds()); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java index 5343fc609..0c6b6e763 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java @@ -7,7 +7,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Configuration; /** - * TODO + * 根据参数动态实例化可用 Bean * * @author wangli * @since 2024/6/11 21:26 @@ -16,16 +16,13 @@ import org.springframework.context.annotation.Configuration; public class StarterFeignClientConfiguration { @Configuration(proxyBeanMethods = false) - @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "manageable", havingValue = "true", matchIfMissing = true) @EnableFeignClients(clients = WorkflowCoreService.class) public static class WorkflowCoreServiceClient { - } @Configuration(proxyBeanMethods = false) - @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "manageable", havingValue = "false") + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "manageable", havingValue = "true") @EnableFeignClients(clients = WorkflowManageService.class) public static class WorkflowManageServiceClient { - } } diff --git a/workflow-engine-support/pom.xml b/workflow-engine-support/pom.xml index 6a40185c4..25007a6f7 100644 --- a/workflow-engine-support/pom.xml +++ b/workflow-engine-support/pom.xml @@ -15,9 +15,30 @@ com.github.javaparser javaparser-core - - cn.axzo.workflow - workflow-engine-spring-boot-starter - + + + + org.codehaus.mojo + exec-maven-plugin + 3.3.0 + + + run-custom-code + process-classes + + java + + + cn.axzo.workflow.support.api.CodeGenerator + + + + compile + + + + + + diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGenerator.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGenerator.java new file mode 100644 index 000000000..3f3861f92 --- /dev/null +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CodeGenerator.java @@ -0,0 +1,17 @@ +package cn.axzo.workflow.support.api; + +/** + * Maven plugin execution entrance + * + * @author wangli + * @since 2024/6/12 10:56 + */ +public class CodeGenerator { + + public static void main(String[] args) throws Exception { + + CoreServiceCodeGeneration.generate(); + ManageServiceCodeGeneration.generate(); + + } +} diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java similarity index 83% rename from workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java rename to workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java index c56d3127b..c313d1728 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGenerator.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java @@ -1,9 +1,5 @@ package cn.axzo.workflow.support.api; -import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; -import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.starter.WorkflowEngineStarterAutoConfiguration; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import com.github.javaparser.ParserConfiguration; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; @@ -24,10 +20,7 @@ import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.Type; import com.github.javaparser.printer.DefaultPrettyPrinter; import com.github.javaparser.printer.Printer; -import com.github.javaparser.utils.CodeGenerationUtils; import com.github.javaparser.utils.SourceRoot; -import lombok.SneakyThrows; -import org.springframework.cloud.openfeign.FeignClient; import java.io.FileWriter; import java.io.IOException; @@ -42,21 +35,19 @@ import java.util.Optional; * @author wangli * @since 2024/6/7 17:14 */ -public class CoreServiceCodeGenerator { +public class CoreServiceCodeGeneration { - @SneakyThrows - public static void main(String[] args) { + public static void generate() throws Exception { String newClassName = "WorkflowCoreService"; - CompilationUnit originFile = parseOriginFile(newClassName); - +// CompilationUnit originFile = parseOriginFile(newClassName); CompilationUnit testGeneric = genericCode("cn.axzo.workflow.starter.api", newClassName); writeToStarter(testGeneric, newClassName); } - @SneakyThrows - private static CompilationUnit parseOriginFile(String newClassName) { - Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineStarterAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/starter/api/"); + private static CompilationUnit parseOriginFile(String newClassName) throws Exception { + String projectRootDir = System.getProperty("user.dir"); + Path sourceCodeRoot = Paths.get(projectRootDir, "/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/"); SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); Printer printer = new DefaultPrettyPrinter(); @@ -84,7 +75,7 @@ public class CoreServiceCodeGenerator { } } - public static CompilationUnit genericCode(String pkg, String newClassName) { + private static CompilationUnit genericCode(String pkg, String newClassName) throws Exception { CompilationUnit cu = new CompilationUnit(pkg); ClassOrInterfaceDeclaration interfaceDeclaration = setCommon(cu, newClassName); @@ -97,13 +88,13 @@ public class CoreServiceCodeGenerator { MethodDeclaration sync = createDefaultMethod("sync", interfaceDeclaration); sync.setJavadocComment("强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + "
\r\n" +
-                "workflowCoreService.sync().createProcessInstance();\r\n" +
+                "  workflowCoreService.sync().createProcessInstance();\r\n" +
                 "
"); MethodDeclaration async = createDefaultMethod("async", interfaceDeclaration); sync.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + "
\r\n" +
-                "workflowCoreService.async().createProcessInstance();\r\n" +
+                "  workflowCoreService.async().createProcessInstance();\r\n" +
                 "
"); } @@ -129,9 +120,9 @@ public class CoreServiceCodeGenerator { return methodDeclaration; } - @SneakyThrows - private static void addMethods(ClassOrInterfaceDeclaration interfaceDeclaration, CompilationUnit cu) { - Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineClientAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/client/feign/"); + private static void addMethods(ClassOrInterfaceDeclaration interfaceDeclaration, CompilationUnit cu) throws Exception { + String projectRootDir = System.getProperty("user.dir"); + Path sourceCodeRoot = Paths.get(projectRootDir, "/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/"); SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); Printer printer = new DefaultPrettyPrinter(); @@ -141,13 +132,13 @@ public class CoreServiceCodeGenerator { List compilationUnits = sourceRoot.getCompilationUnits(); NodeList> targetMethods = interfaceDeclaration.getMembers(); for (CompilationUnit apiCU : compilationUnits) { - if (!apiCU.getPrimaryType().filter(e -> e.getAnnotationByClass(Manageable.class).isPresent()).isPresent()) { + if (!apiCU.getPrimaryType().filter(e -> e.getAnnotationByName("Manageable").isPresent()).isPresent()) { addImports(apiCU, cu); // 类上含有 @Manageable,不进行解析 String interfaceName = apiCU.getPrimaryTypeName().get(); List methods = apiCU.getInterfaceByName(interfaceName).get().findAll(MethodDeclaration.class); for (MethodDeclaration method : methods) { - if (!method.getAnnotationByClass(Manageable.class).isPresent()) { + if (!method.getAnnotationByName("Manageable").isPresent()) { MethodDeclaration methodDeclaration = method.clone(); methodDeclaration.setType(changeReturnType(methodDeclaration.getType())); targetMethods.add(methodDeclaration); @@ -177,10 +168,10 @@ public class CoreServiceCodeGenerator { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service"); - classOrInterfaceDeclaration.addAndGetAnnotation(FeignClient.class) - .addPair("name", new StringLiteralExpr("workflow-engine-starter")) + classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") + .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) - .addPair("configuration", new ClassExpr(new ClassOrInterfaceType(null, WorkflowEngineStarterFeignConfiguration.class.getSimpleName()))); + .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC", true, false); diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java similarity index 73% rename from workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java rename to workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index 00fb79bcb..ffa4a7831 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGenerator.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -1,8 +1,5 @@ package cn.axzo.workflow.support.api; -import cn.axzo.workflow.client.config.WorkflowEngineClientAutoConfiguration; -import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import com.github.javaparser.ParserConfiguration; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; @@ -23,10 +20,7 @@ import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.Type; import com.github.javaparser.printer.DefaultPrettyPrinter; import com.github.javaparser.printer.Printer; -import com.github.javaparser.utils.CodeGenerationUtils; import com.github.javaparser.utils.SourceRoot; -import lombok.SneakyThrows; -import org.springframework.cloud.openfeign.FeignClient; import java.io.FileWriter; import java.io.IOException; @@ -40,9 +34,9 @@ import java.util.List; * @author wangli * @since 2024/6/11 17:38 */ -public class ManageServiceCodeGenerator { - @SneakyThrows - public static void main(String[] args) { +public class ManageServiceCodeGeneration { + + public static void generate() throws Exception { String newClassName = "WorkflowManageService"; CompilationUnit testGeneric = genericCode("cn.axzo.workflow.starter.api", newClassName); @@ -60,7 +54,7 @@ public class ManageServiceCodeGenerator { } } - public static CompilationUnit genericCode(String pkg, String newClassName) { + private static CompilationUnit genericCode(String pkg, String newClassName) throws Exception { CompilationUnit cu = new CompilationUnit(pkg); ClassOrInterfaceDeclaration interfaceDeclaration = setCommon(cu, newClassName); @@ -73,20 +67,20 @@ public class ManageServiceCodeGenerator { MethodDeclaration sync = createDefaultMethod("sync", interfaceDeclaration); sync.setJavadocComment("强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + "
\r\n" +
-                "workflowCoreService.sync().createProcessInstance();\r\n" +
+                "  workflowManageService.sync().getTenantIds();\r\n" +
                 "
"); MethodDeclaration async = createDefaultMethod("async", interfaceDeclaration); - sync.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + + async.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + "
\r\n" +
-                "workflowCoreService.async().createProcessInstance();\r\n" +
+                "  workflowManageService.async().getTenantIds();\r\n" +
                 "
"); } private static MethodDeclaration createDefaultMethod(String methodName, ClassOrInterfaceDeclaration interfaceDeclaration) { // 将sync方法添加到WorkflowCoreService类中 MethodDeclaration methodDeclaration = interfaceDeclaration.addMethod(methodName, Modifier.Keyword.DEFAULT); - methodDeclaration.setType(new ClassOrInterfaceType("WorkflowCoreService")); + methodDeclaration.setType(new ClassOrInterfaceType("WorkflowManageService")); // 创建方法体 BlockStmt methodBody = new BlockStmt(); @@ -105,9 +99,9 @@ public class ManageServiceCodeGenerator { return methodDeclaration; } - @SneakyThrows - private static void addMethods(ClassOrInterfaceDeclaration interfaceDeclaration, CompilationUnit cu) { - Path sourceCodeRoot = CodeGenerationUtils.mavenModuleRoot(WorkflowEngineClientAutoConfiguration.class).resolve("src/main/java/cn/axzo/workflow/client/feign/"); + private static void addMethods(ClassOrInterfaceDeclaration interfaceDeclaration, CompilationUnit cu) throws Exception { + String projectRootDir = System.getProperty("user.dir"); + Path sourceCodeRoot = Paths.get(projectRootDir, "/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/"); SourceRoot sourceRoot = new SourceRoot(sourceCodeRoot); sourceRoot.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8); Printer printer = new DefaultPrettyPrinter(); @@ -117,18 +111,30 @@ public class ManageServiceCodeGenerator { List compilationUnits = sourceRoot.getCompilationUnits(); NodeList> targetMethods = interfaceDeclaration.getMembers(); for (CompilationUnit apiCU : compilationUnits) { - if (!apiCU.getPrimaryType().filter(e -> e.getAnnotationByClass(Manageable.class).isPresent()).isPresent()) { + // 如果类上包含 @Manageable 注解,则直接将所有方法解析进新目标接口中 + if (apiCU.getPrimaryType().filter(e -> e.getAnnotationByName("Manageable").isPresent()).isPresent()) { addImports(apiCU, cu); // 类上含有 @Manageable,不进行解析 - String interfaceName = apiCU.getPrimaryTypeName().get(); - List methods = apiCU.getInterfaceByName(interfaceName).get().findAll(MethodDeclaration.class); - for (MethodDeclaration method : methods) { - if (!method.getAnnotationByClass(Manageable.class).isPresent()) { - MethodDeclaration methodDeclaration = method.clone(); - methodDeclaration.setType(changeReturnType(methodDeclaration.getType())); - targetMethods.add(methodDeclaration); - } - } + addMethod0(apiCU, targetMethods, false); + } else { + addImports(apiCU, cu); + addMethod0(apiCU, targetMethods, true); + } + } + } + + private static void addMethod0(CompilationUnit apiCU, NodeList> targetMethods, boolean containAnnotation) { + String interfaceName = apiCU.getPrimaryTypeName().get(); + List methods = apiCU.getInterfaceByName(interfaceName).get().findAll(MethodDeclaration.class); + for (MethodDeclaration method : methods) { + if (containAnnotation && method.getAnnotationByName("Manageable").isPresent()) { + MethodDeclaration methodDeclaration = method.clone(); + methodDeclaration.setType(changeReturnType(methodDeclaration.getType())); + targetMethods.add(methodDeclaration); + } else if (!containAnnotation && !method.getAnnotationByName("Manageable").isPresent()) { + MethodDeclaration methodDeclaration = method.clone(); + methodDeclaration.setType(changeReturnType(methodDeclaration.getType())); + targetMethods.add(methodDeclaration); } } } @@ -153,10 +159,10 @@ public class ManageServiceCodeGenerator { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service"); - classOrInterfaceDeclaration.addAndGetAnnotation(FeignClient.class) - .addPair("name", new StringLiteralExpr("workflow-engine-starter")) + classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") + .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) - .addPair("configuration", new ClassExpr(new ClassOrInterfaceType(null, WorkflowEngineStarterFeignConfiguration.class.getSimpleName()))); + .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC", true, false); From d71619873db2ba1072d1bf801e636ee741ec730a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 11:06:36 +0800 Subject: [PATCH 091/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E7=94=9F=E6=88=90=E5=A5=BD=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 74 +++++++++++++------ .../starter/api/WorkflowManageService.java | 23 +++--- 2 files changed, 59 insertions(+), 38 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index d7abe057d..0a0899d04 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,43 +1,69 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.util.ThreadUtil; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.axzo.workflow.common.util.ThreadUtil; + +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + +import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.azxo.framework.common.model.CommonResponse; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; -import javax.annotation.Nullable; import javax.validation.constraints.NotBlank; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PutMapping; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import javax.validation.constraints.NotEmpty; /** * Workflow Engine Starter Core Service */ -@FeignClient(name = "workflow-engine-starter", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { /** @@ -258,7 +284,7 @@ public interface WorkflowCoreService { /** * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 *
-     * workflowCoreService.async().createProcessInstance();
+     *   workflowCoreService.async().createProcessInstance();
      * 
*/ default WorkflowCoreService sync() { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index f2cd19cb3..1b3c52732 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,21 +1,16 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; -import org.springframework.cloud.openfeign.FeignClient; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import cn.axzo.workflow.common.util.ThreadUtil; - import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; - import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.azxo.framework.common.model.CommonResponse; +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; - import java.util.List; - import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; @@ -29,10 +24,8 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; - import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; - import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; @@ -50,10 +43,8 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePa import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import com.fasterxml.jackson.databind.node.ObjectNode; - import javax.annotation.Nullable; import java.util.Map; - import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; @@ -77,9 +68,7 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstance import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; - import javax.validation.constraints.NotEmpty; - import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; @@ -629,9 +618,9 @@ public interface WorkflowManageService { Void delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId, @RequestParam(required = false) Boolean cascade); /** - * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 + * 强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法 *
-     *   workflowManageService.async().getTenantIds();
+     *   workflowManageService.sync().getTenantIds();
      * 
*/ default WorkflowManageService sync() { @@ -639,6 +628,12 @@ public interface WorkflowManageService { return this; } + /** + * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 + *
+     *   workflowManageService.async().getTenantIds();
+     * 
+ */ default WorkflowManageService async() { ThreadUtil.set(ASYNC); return this; From 86d74201f7016f5143d0525436d2105f1b1a1a28 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:51:31 +0800 Subject: [PATCH 092/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20workflow-auto-gen=20=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-api/pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/workflow-engine-api/pom.xml b/workflow-engine-api/pom.xml index 7f088af3c..11ba8fffc 100644 --- a/workflow-engine-api/pom.xml +++ b/workflow-engine-api/pom.xml @@ -23,10 +23,6 @@ workflow-engine-common ${project.version} - io.github.openfeign feign-httpclient From 54ec158808c485d92ccb915aadda72312144727c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:51:53 +0800 Subject: [PATCH 093/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20starter=20=E4=B8=AD=E7=9A=84=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/AsyncNotSupportException.java | 13 ------------- .../exception/CreateProcessInstanceException.java | 13 ------------- .../exception/ManagementDisabledException.java | 13 ------------- .../exception/WorkflowRequestParserException.java | 13 ------------- 4 files changed, 52 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java deleted file mode 100644 index f129865b5..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/AsyncNotSupportException.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.workflow.starter.common.exception; - -/** - * TODO - * - * @author wangli - * @since 2024/5/21 17:59 - */ -public class AsyncNotSupportException extends WorkflowEngineStarterException { - public AsyncNotSupportException(String message) { - super(message); - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java deleted file mode 100644 index d3cda1def..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/CreateProcessInstanceException.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.workflow.starter.common.exception; - -/** - * TODO - * - * @author wangli - * @since 2024/5/22 13:41 - */ -public class CreateProcessInstanceException extends WorkflowEngineStarterException { - public CreateProcessInstanceException(String message) { - super(message); - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java deleted file mode 100644 index c7701dcfe..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/ManagementDisabledException.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.workflow.starter.common.exception; - -/** - * TODO - * - * @author wangli - * @since 2024/5/21 17:59 - */ -public class ManagementDisabledException extends WorkflowEngineStarterException { - public ManagementDisabledException(String message) { - super(message); - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java deleted file mode 100644 index 15bb4142c..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRequestParserException.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.workflow.starter.common.exception; - -/** - * 工作流 RPC 动作异步,解析 feign.Request 中 HTTP 协议的请求参数异常 - * - * @author wangli - * @since 2024/6/3 10:48 - */ -public class WorkflowRequestParserException extends RuntimeException { - public WorkflowRequestParserException(String message) { - super(message); - } -} From f66fbad91ae2c1c514843e8b05ca99137e2874ae Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:53:23 +0800 Subject: [PATCH 094/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=B9=BF=E6=92=AD=20MQ=20=E4=BA=8B=E4=BB=B6=E7=9B=91?= =?UTF-8?q?=E5=90=AC=E5=A4=84=E7=90=86=E5=A4=B1=E8=B4=A5=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E7=9A=84=E5=88=9D=E5=A7=8B=E5=8C=96=E7=AD=96=E7=95=A5=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81=E7=9A=84=E6=A8=A1=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E5=9C=A8=E5=90=AF=E5=8A=A8=E6=97=B6=E6=8A=9B=E9=94=99=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...adcastListenerConfigurationProperties.java | 4 +- ...orkflowEngineStarterAutoConfiguration.java | 13 +++--- .../WorkflowEngineStarterException.java | 6 ++- .../WorkflowListenerExeException.java | 41 ------------------- .../WorkflowListenerExecutionException.java | 13 ++++++ .../WorkflowUnsupportedException.java | 18 ++++++++ 6 files changed, 45 insertions(+), 50 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExecutionException.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowUnsupportedException.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java index 57079bd3c..a826c4e0e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java @@ -60,10 +60,10 @@ public class BroadcastListenerConfigurationProperties { /** * 初始等待时间,单位:毫秒 */ - private int waitTimeInMs = 50; + private int waitTimeInMs = 1500; /** - * 重试累乘因子 + * 重试累乘因子, 意味多次重试时,每次重试间隔为 waitTimeInMs * waitIncreaseFactor 毫秒 */ private int waitIncreaseFactor = 3; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 8ac831880..ff117e362 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter; import cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum; +import cn.axzo.workflow.starter.common.exception.WorkflowUnsupportedException; import cn.axzo.workflow.starter.handler.MessageNotificationEventHandler; import cn.axzo.workflow.starter.handler.ProcessActivityEventHandler; import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler; @@ -8,7 +9,6 @@ import cn.axzo.workflow.starter.handler.ProcessTaskEventHandler; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import cn.axzo.workflow.starter.handler.execute.interceptor.ExecuteInterceptor; import cn.axzo.workflow.starter.handler.execute.interceptor.ExecutorInvoker; -import cn.axzo.workflow.starter.handler.execute.interceptor.FailBackInterceptor; import cn.axzo.workflow.starter.handler.execute.interceptor.FailFastInterceptor; import cn.axzo.workflow.starter.handler.execute.interceptor.FailOverInterceptor; import cn.axzo.workflow.starter.handler.execute.interceptor.LogInterceptor; @@ -35,6 +35,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; import java.util.ArrayList; import java.util.List; @@ -47,8 +48,6 @@ import java.util.List; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) -//@EnableFeignClients(clients = {WorkflowCoreService.class}) -//@EnableFeignClients(clients = {WorkflowManageService.class}) @Import({StarterFeignClientConfiguration.class, StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class}) public class WorkflowEngineStarterAutoConfiguration { @@ -102,7 +101,8 @@ public class WorkflowEngineStarterAutoConfiguration { log.info("workflow engine starter fail handle type : {}", failHandleType); switch (failHandleType) { case FAIL_BACK: - return new FailBackInterceptor(); +// return new FailBackInterceptor(); + throw new WorkflowUnsupportedException("暂不支持该模式, 请调整 MQ 处理失败策略, workflow.engine.starter.broadcast.fail-handle-type"); case FAIL_FAST: return new FailFastInterceptor(); case FAIL_OVER: @@ -137,7 +137,8 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean - public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt) { - return new WorkflowEngineStarterDefaultMQMonitor(defaultMQAdminExt); + public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt, + Environment environment) { + return new WorkflowEngineStarterDefaultMQMonitor(defaultMQAdminExt, environment); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java index d74115e10..2cf0712b7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java @@ -1,7 +1,7 @@ package cn.axzo.workflow.starter.common.exception; /** - * TODO + * 流程引擎 starter 的异常类 * * @author wangli * @since 2024/5/21 17:57 @@ -11,4 +11,8 @@ public class WorkflowEngineStarterException extends RuntimeException { public WorkflowEngineStarterException(String message) { super(message); } + + public WorkflowEngineStarterException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java deleted file mode 100644 index 5c6ec1fcc..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExeException.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.axzo.workflow.starter.common.exception; - -public class WorkflowListenerExeException extends RuntimeException { - private int code; - - public WorkflowListenerExeException(String message) { - super(message); - } - - public WorkflowListenerExeException() { - super(); - } - - public WorkflowListenerExeException(String message, Throwable cause) { - super(message, cause); - } - - public WorkflowListenerExeException(Throwable cause) { - super(cause); - } - - public WorkflowListenerExeException(int code) { - super(); - this.code = code; - } - - public WorkflowListenerExeException(int code, String message, Throwable cause) { - super(message, cause); - this.code = code; - } - - public WorkflowListenerExeException(int code, String message) { - super(message); - this.code = code; - } - - public WorkflowListenerExeException(int code, Throwable cause) { - super(cause); - this.code = code; - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExecutionException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExecutionException.java new file mode 100644 index 000000000..163dccd2e --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowListenerExecutionException.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.starter.common.exception; + +public class WorkflowListenerExecutionException extends WorkflowEngineStarterException { + + public WorkflowListenerExecutionException(String message) { + super(message); + } + + public WorkflowListenerExecutionException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowUnsupportedException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowUnsupportedException.java new file mode 100644 index 000000000..09bda2345 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowUnsupportedException.java @@ -0,0 +1,18 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * 不支持的操作的异常类 + * + * @author wangli + * @since 2024/6/12 15:25 + */ +public class WorkflowUnsupportedException extends WorkflowEngineStarterException { + + public WorkflowUnsupportedException(String message) { + super(message); + } + + public WorkflowUnsupportedException(String message, Throwable cause) { + super(message, cause); + } +} From 525ee7c12460661027079e78e0ceacdf93b2e823 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:53:37 +0800 Subject: [PATCH 095/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E4=B8=80=E4=BA=9B=E6=97=A0=E7=94=A8=E7=9A=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/WorkflowEngineStarterFeign.java | 25 -- .../ext/WorkflowEngineStarterTarget.java | 27 -- .../ext/WorkflowEngineStarterTargeter.java | 36 -- .../src/main/java/feign/ReflectiveFeign.java | 415 ------------------ 4 files changed, 503 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java deleted file mode 100644 index 3e2676a47..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeign.java +++ /dev/null @@ -1,25 +0,0 @@ -//package cn.axzo.workflow.starter.feign.ext; -// -//import feign.Feign; -//import feign.Target; -// -///** -// * TODO -// * -// * @author wangli -// * @since 2024/6/11 15:40 -// */ -//public class WorkflowEngineStarterFeign { -// -// public static WorkflowEngineStarterFeign.Builder builder() { -// return new WorkflowEngineStarterFeign.Builder(); -// } -// -// public static final class Builder extends Feign.Builder { -// -// @Override -// public T target(Target target) { -// return super.build().newInstance(target); -// } -// } -//} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java deleted file mode 100644 index 909c14041..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTarget.java +++ /dev/null @@ -1,27 +0,0 @@ -//package cn.axzo.workflow.starter.feign.ext; -// -//import feign.Target; -// -///** -// * TODO -// * -// * @author wangli -// * @since 2024/6/11 17:00 -// */ -//public class WorkflowEngineStarterTarget extends Target.HardCodedTarget { -// private final Class manageableInterface; -// -// public WorkflowEngineStarterTarget(Class type, String url, Class manageableInterface) { -// super(type, url); -// this.manageableInterface = manageableInterface; -// } -// -// public WorkflowEngineStarterTarget(Class type, String name, String url, Class manageableInterface) { -// super(type, name, url); -// this.manageableInterface = manageableInterface; -// } -// -// public Class getManageableInterface() { -// return manageableInterface; -// } -//} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java deleted file mode 100644 index 9fe61c5e9..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterTargeter.java +++ /dev/null @@ -1,36 +0,0 @@ -//package cn.axzo.workflow.starter.feign.ext; -// -//import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -//import cn.axzo.workflow.starter.api.WorkflowManageService; -//import feign.Feign; -//import feign.Target; -//import org.springframework.cloud.openfeign.FeignClientFactoryBean; -//import org.springframework.cloud.openfeign.FeignContext; -//import org.springframework.cloud.openfeign.Targeter; -// -///** -// * TODO -// * -// * @author wangli -// * @since 2024/6/11 16:12 -// */ -//public class WorkflowEngineStarterTargeter implements Targeter { -// private final WorkflowEngineStarterProperties properties; -// -// public WorkflowEngineStarterTargeter(WorkflowEngineStarterProperties starterProperties) { -// this.properties = starterProperties; -// } -// -// @Override -// public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { -// if (!(feign instanceof WorkflowEngineStarterFeign.Builder)) { -// return feign.target(target); -// } -// Class clazz = null; -// if (properties.getManageable()) { -// clazz = WorkflowManageService.class; -// } -// Target newTarget = new WorkflowEngineStarterTarget<>(target.type(), target.name(), target.url(), clazz); -// return feign.target(newTarget); -// } -//} diff --git a/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java b/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java deleted file mode 100644 index fa6f83310..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/feign/ReflectiveFeign.java +++ /dev/null @@ -1,415 +0,0 @@ -///** -// * Copyright 2012-2020 The Feign Authors -// *

-// * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -// * in compliance with the License. You may obtain a copy of the License at -// *

-// * http://www.apache.org/licenses/LICENSE-2.0 -// *

-// * Unless required by applicable law or agreed to in writing, software distributed under the License -// * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -// * or implied. See the License for the specific language governing permissions and limitations under -// * the License. -// */ -//package feign; -// -//import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterTarget; -//import feign.InvocationHandlerFactory.MethodHandler; -//import feign.Param.Expander; -//import feign.Request.Options; -//import feign.codec.Decoder; -//import feign.codec.EncodeException; -//import feign.codec.Encoder; -//import feign.codec.ErrorDecoder; -//import feign.template.UriUtils; -// -//import java.lang.reflect.InvocationHandler; -//import java.lang.reflect.Method; -//import java.lang.reflect.Proxy; -//import java.util.ArrayList; -//import java.util.Collection; -//import java.util.Iterator; -//import java.util.LinkedHashMap; -//import java.util.LinkedList; -//import java.util.List; -//import java.util.Map; -//import java.util.Map.Entry; -//import java.util.Objects; -// -//import static feign.Util.checkArgument; -//import static feign.Util.checkNotNull; -// -//public class ReflectiveFeign extends Feign { -// -// private final ParseHandlersByName targetToHandlersByName; -// private final InvocationHandlerFactory factory; -// private final QueryMapEncoder queryMapEncoder; -// -// ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, -// QueryMapEncoder queryMapEncoder) { -// this.targetToHandlersByName = targetToHandlersByName; -// this.factory = factory; -// this.queryMapEncoder = queryMapEncoder; -// } -// -// /** -// * creates an api binding to the {@code target}. As this invokes reflection, care should be taken -// * to cache the result. -// */ -// @SuppressWarnings("unchecked") -// @Override -// public T newInstance(Target target) { -// Map nameToHandler = targetToHandlersByName.apply(target); -// Map methodToHandler = new LinkedHashMap(); -// List defaultMethodHandlers = new LinkedList(); -// -// for (Method method : target.type().getMethods()) { -// if (method.getDeclaringClass() == Object.class) { -// continue; -// } else if (Util.isDefault(method)) { -// DefaultMethodHandler handler = new DefaultMethodHandler(method); -// defaultMethodHandlers.add(handler); -// methodToHandler.put(method, handler); -// } else { -// methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); -// } -// } -// InvocationHandler handler = factory.create(target, methodToHandler); -// List> classList = new ArrayList<>(); -// classList.add(target.type()); -// if (target instanceof WorkflowEngineStarterTarget) { -// Class manageableInterface = ((WorkflowEngineStarterTarget) target).getManageableInterface(); -// if (Objects.nonNull(manageableInterface)) { -// classList.add(manageableInterface); -// } -// } -// T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), -// classList.toArray(new Class[0]), handler); -// -// for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { -// defaultMethodHandler.bindTo(proxy); -// } -// return proxy; -// } -// -// static class FeignInvocationHandler implements InvocationHandler { -// -// private final Target target; -// private final Map dispatch; -// -// FeignInvocationHandler(Target target, Map dispatch) { -// this.target = checkNotNull(target, "target"); -// this.dispatch = checkNotNull(dispatch, "dispatch for %s", target); -// } -// -// @Override -// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { -// if ("equals".equals(method.getName())) { -// try { -// Object otherHandler = -// args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; -// return equals(otherHandler); -// } catch (IllegalArgumentException e) { -// return false; -// } -// } else if ("hashCode".equals(method.getName())) { -// return hashCode(); -// } else if ("toString".equals(method.getName())) { -// return toString(); -// } -// -// return dispatch.get(method).invoke(args); -// } -// -// @Override -// public boolean equals(Object obj) { -// if (obj instanceof FeignInvocationHandler) { -// FeignInvocationHandler other = (FeignInvocationHandler) obj; -// return target.equals(other.target); -// } -// return false; -// } -// -// @Override -// public int hashCode() { -// return target.hashCode(); -// } -// -// @Override -// public String toString() { -// return target.toString(); -// } -// } -// -// static final class ParseHandlersByName { -// -// private final Contract contract; -// private final Options options; -// private final Encoder encoder; -// private final Decoder decoder; -// private final ErrorDecoder errorDecoder; -// private final QueryMapEncoder queryMapEncoder; -// private final SynchronousMethodHandler.Factory factory; -// -// ParseHandlersByName( -// Contract contract, -// Options options, -// Encoder encoder, -// Decoder decoder, -// QueryMapEncoder queryMapEncoder, -// ErrorDecoder errorDecoder, -// SynchronousMethodHandler.Factory factory) { -// this.contract = contract; -// this.options = options; -// this.factory = factory; -// this.errorDecoder = errorDecoder; -// this.queryMapEncoder = queryMapEncoder; -// this.encoder = checkNotNull(encoder, "encoder"); -// this.decoder = checkNotNull(decoder, "decoder"); -// } -// -// public Map apply(Target target) { -// List metadata = contract.parseAndValidateMetadata(target.type()); -// Map result = new LinkedHashMap(); -// for (MethodMetadata md : metadata) { -// BuildTemplateByResolvingArgs buildTemplate; -// if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { -// buildTemplate = -// new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); -// } else if (md.bodyIndex() != null) { -// buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); -// } else { -// buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target); -// } -// if (md.isIgnored()) { -// result.put(md.configKey(), args -> { -// throw new IllegalStateException(md.configKey() + " is not a method handled by feign"); -// }); -// } else { -// result.put(md.configKey(), -// factory.create(target, md, buildTemplate, options, decoder, errorDecoder)); -// } -// } -// return result; -// } -// } -// -// private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory { -// -// private final QueryMapEncoder queryMapEncoder; -// -// protected final MethodMetadata metadata; -// protected final Target target; -// private final Map indexToExpander = new LinkedHashMap(); -// -// private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder, -// Target target) { -// this.metadata = metadata; -// this.target = target; -// this.queryMapEncoder = queryMapEncoder; -// if (metadata.indexToExpander() != null) { -// indexToExpander.putAll(metadata.indexToExpander()); -// return; -// } -// if (metadata.indexToExpanderClass().isEmpty()) { -// return; -// } -// for (Entry> indexToExpanderClass : metadata -// .indexToExpanderClass().entrySet()) { -// try { -// indexToExpander -// .put(indexToExpanderClass.getKey(), indexToExpanderClass.getValue().newInstance()); -// } catch (InstantiationException e) { -// throw new IllegalStateException(e); -// } catch (IllegalAccessException e) { -// throw new IllegalStateException(e); -// } -// } -// } -// -// @Override -// public RequestTemplate create(Object[] argv) { -// RequestTemplate mutable = RequestTemplate.from(metadata.template()); -// mutable.feignTarget(target); -// if (metadata.urlIndex() != null) { -// int urlIndex = metadata.urlIndex(); -// checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex); -// mutable.target(String.valueOf(argv[urlIndex])); -// } -// Map varBuilder = new LinkedHashMap(); -// for (Entry> entry : metadata.indexToName().entrySet()) { -// int i = entry.getKey(); -// Object value = argv[entry.getKey()]; -// if (value != null) { // Null values are skipped. -// if (indexToExpander.containsKey(i)) { -// value = expandElements(indexToExpander.get(i), value); -// } -// for (String name : entry.getValue()) { -// varBuilder.put(name, value); -// } -// } -// } -// -// RequestTemplate template = resolve(argv, mutable, varBuilder); -// if (metadata.queryMapIndex() != null) { -// // add query map parameters after initial resolve so that they take -// // precedence over any predefined values -// Object value = argv[metadata.queryMapIndex()]; -// Map queryMap = toQueryMap(value); -// template = addQueryMapQueryParameters(queryMap, template); -// } -// -// if (metadata.headerMapIndex() != null) { -// template = -// addHeaderMapHeaders((Map) argv[metadata.headerMapIndex()], template); -// } -// -// return template; -// } -// -// private Map toQueryMap(Object value) { -// if (value instanceof Map) { -// return (Map) value; -// } -// try { -// return queryMapEncoder.encode(value); -// } catch (EncodeException e) { -// throw new IllegalStateException(e); -// } -// } -// -// private Object expandElements(Expander expander, Object value) { -// if (value instanceof Iterable) { -// return expandIterable(expander, (Iterable) value); -// } -// return expander.expand(value); -// } -// -// private List expandIterable(Expander expander, Iterable value) { -// List values = new ArrayList(); -// for (Object element : value) { -// if (element != null) { -// values.add(expander.expand(element)); -// } -// } -// return values; -// } -// -// @SuppressWarnings("unchecked") -// private RequestTemplate addHeaderMapHeaders(Map headerMap, -// RequestTemplate mutable) { -// for (Entry currEntry : headerMap.entrySet()) { -// Collection values = new ArrayList(); -// -// Object currValue = currEntry.getValue(); -// if (currValue instanceof Iterable) { -// Iterator iter = ((Iterable) currValue).iterator(); -// while (iter.hasNext()) { -// Object nextObject = iter.next(); -// values.add(nextObject == null ? null : nextObject.toString()); -// } -// } else { -// values.add(currValue == null ? null : currValue.toString()); -// } -// -// mutable.header(currEntry.getKey(), values); -// } -// return mutable; -// } -// -// @SuppressWarnings("unchecked") -// private RequestTemplate addQueryMapQueryParameters(Map queryMap, -// RequestTemplate mutable) { -// for (Entry currEntry : queryMap.entrySet()) { -// Collection values = new ArrayList(); -// -// boolean encoded = metadata.queryMapEncoded(); -// Object currValue = currEntry.getValue(); -// if (currValue instanceof Iterable) { -// Iterator iter = ((Iterable) currValue).iterator(); -// while (iter.hasNext()) { -// Object nextObject = iter.next(); -// values.add(nextObject == null ? null -// : encoded ? nextObject.toString() -// : UriUtils.encode(nextObject.toString())); -// } -// } else if (currValue instanceof Object[]) { -// for (Object value : (Object[]) currValue) { -// values.add(value == null ? null -// : encoded ? value.toString() : UriUtils.encode(value.toString())); -// } -// } else { -// values.add(currValue == null ? null -// : encoded ? currValue.toString() : UriUtils.encode(currValue.toString())); -// } -// -// mutable.query(encoded ? currEntry.getKey() : UriUtils.encode(currEntry.getKey()), values); -// } -// return mutable; -// } -// -// protected RequestTemplate resolve(Object[] argv, -// RequestTemplate mutable, -// Map variables) { -// return mutable.resolve(variables); -// } -// } -// -// private static class BuildFormEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { -// -// private final Encoder encoder; -// -// private BuildFormEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, -// QueryMapEncoder queryMapEncoder, Target target) { -// super(metadata, queryMapEncoder, target); -// this.encoder = encoder; -// } -// -// @Override -// protected RequestTemplate resolve(Object[] argv, -// RequestTemplate mutable, -// Map variables) { -// Map formVariables = new LinkedHashMap(); -// for (Entry entry : variables.entrySet()) { -// if (metadata.formParams().contains(entry.getKey())) { -// formVariables.put(entry.getKey(), entry.getValue()); -// } -// } -// try { -// encoder.encode(formVariables, Encoder.MAP_STRING_WILDCARD, mutable); -// } catch (EncodeException e) { -// throw e; -// } catch (RuntimeException e) { -// throw new EncodeException(e.getMessage(), e); -// } -// return super.resolve(argv, mutable, variables); -// } -// } -// -// private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs { -// -// private final Encoder encoder; -// -// private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, -// QueryMapEncoder queryMapEncoder, Target target) { -// super(metadata, queryMapEncoder, target); -// this.encoder = encoder; -// } -// -// @Override -// protected RequestTemplate resolve(Object[] argv, -// RequestTemplate mutable, -// Map variables) { -// Object body = argv[metadata.bodyIndex()]; -// checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex()); -// try { -// encoder.encode(body, metadata.bodyType(), mutable); -// } catch (EncodeException e) { -// throw e; -// } catch (RuntimeException e) { -// throw new EncodeException(e.getMessage(), e); -// } -// return super.resolve(argv, mutable, variables); -// } -// } -//} From e3a1a6fdc564506d6e596173b89596ebd98a087b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:54:34 +0800 Subject: [PATCH 096/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=BC=95?= =?UTF-8?q?=E6=93=8E=E5=B9=BF=E6=92=AD=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=99=A8=E5=A4=B1=E8=B4=A5=E7=AD=96=E7=95=A5=E7=9A=84=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/StarterBroadcastMQConfiguration.java | 6 ++---- .../starter/StarterRPCInvokeMQConfiguration.java | 2 +- .../execute/interceptor/FailFastInterceptor.java | 4 ++-- .../execute/interceptor/FailOverInterceptor.java | 10 +++++----- .../broadcast/consumer/AbstractWorkflowListener.java | 1 + 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index d8b0ebe0a..effbf6545 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -58,10 +58,7 @@ public class StarterBroadcastMQConfiguration { @ConditionalOnMissingBean(EventHandlerRepository.class) public EventHandlerRepository eventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { - log.warn("MQ, handle warning {}", logText, ex); - if (Objects.nonNull(ex)) { - throw new RuntimeException(ex); - } + log.warn("Workflow Engine Starter MQ, handle warning {}", logText, ex); }); } @@ -83,6 +80,7 @@ public class StarterBroadcastMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.ORDERLY, + maxReconsumeTimes = 0, nameServer = "${rocketmq.name-server}" ) public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 34aee44a6..e4167cbdc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -161,7 +161,7 @@ public class StarterRPCInvokeMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, - maxReconsumeTimes = 3, // TODO 发布时需调整为 7, 总共耗时在 15min 内 + maxReconsumeTimes = 7, // 发布时需调整为 7, 总共耗时在 15min 内 replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java index 2cd6d0ef4..f9eaba79c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; -import cn.axzo.workflow.starter.common.exception.WorkflowListenerExeException; +import cn.axzo.workflow.starter.common.exception.WorkflowListenerExecutionException; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; @@ -15,7 +15,7 @@ public final class FailFastInterceptor extends AbstractListenerInterceptor { try { getNext().execute(executor, consumer, t); } catch (Exception e) { - throw new WorkflowListenerExeException( + throw new WorkflowListenerExecutionException( "Failed to invoke the method " // + methodName + ". Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index aeaf8296d..b605c5c12 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -21,9 +21,9 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { } public FailOverInterceptor(int numOfRetries, int waitTimeInMs, int waitIncreaseFactor) { - this.numOfRetries = numOfRetries; - this.waitTimeInMs = waitTimeInMs; - this.waitIncreaseFactor = waitIncreaseFactor; + this.numOfRetries = 0 == Math.abs(numOfRetries) ? this.numOfRetries : Math.abs(numOfRetries); + this.waitTimeInMs = Math.abs(waitTimeInMs); + this.waitIncreaseFactor = Math.abs(waitIncreaseFactor); } @Override @@ -32,7 +32,7 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { int failedAttempts = 0; do { if (failedAttempts > 0) { - LOGGER.info("Waiting for {}ms before retrying the command.", waitTime); + LOGGER.info("Waiting for {} ms before retrying the command.", waitTime); waitBeforeRetry(waitTime); waitTime *= waitIncreaseFactor; } @@ -40,7 +40,7 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { getNext().execute(executor, consumer, t); return; } catch (Exception e) { - LOGGER.info("Caught exception: {}", e.getMessage(), e); + LOGGER.error("Workflow Engine Starter Caught exception: {}", e.getMessage(), e); } failedAttempts++; } while (failedAttempts <= numOfRetries); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java index 7b39ab3ea..f0c06c3f1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java @@ -56,6 +56,7 @@ public abstract class AbstractWorkflowListener Date: Wed, 12 Jun 2024 15:54:57 +0800 Subject: [PATCH 097/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=20MQ=20=E7=9B=91=E6=8E=A7=E7=9A=84=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 4 - ...WorkflowEngineStarterDefaultMQMonitor.java | 107 +++++++++++++++++- ...kflowEngineStarterMQMonitorController.java | 25 ++-- 3 files changed, 120 insertions(+), 16 deletions(-) diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index e19372f30..b9be7e34a 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -19,10 +19,6 @@ cn.axzo.workflow workflow-engine-api - cn.axzo.framework.rocketmq axzo-common-rocketmq diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 9f23ae190..65d98396a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -1,6 +1,20 @@ package cn.axzo.workflow.starter.mq.monitor; +import lombok.SneakyThrows; +import org.apache.rocketmq.common.admin.ConsumeStats; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.SmartLifecycle; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; /** * 用于监控 Starter 关注的 Topic 相关的 Producer 与 Consumer 信息 @@ -8,11 +22,100 @@ import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; * @author wangli * @since 2024/6/6 10:04 */ -public class WorkflowEngineStarterDefaultMQMonitor { +public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { + private static final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterDefaultMQMonitor.class); private final DefaultMQAdminExt defaultMQAdminExt; + private final Environment environment; + private final ThreadPoolTaskScheduler taskScheduler; + private final AtomicBoolean running = new AtomicBoolean(false); + private ConsumeStats broadcastConsumeStats; + private ConsumeStats rpcConsumeStats; + private final Map messageQueue = new HashMap<>(); - public WorkflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt) { + public WorkflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt, Environment environment) { this.defaultMQAdminExt = defaultMQAdminExt; + this.environment = environment; + this.taskScheduler = init(); + } + + private ThreadPoolTaskScheduler init() { + ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); + taskScheduler.setBeanName("Workflow-Engine-Watch-MQ-Scheduler"); + taskScheduler.initialize(); + return taskScheduler; + } + + @SneakyThrows + public void mqWatch() { + log.info("time is :{}", System.currentTimeMillis()); + String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); + String applicationName = environment.getProperty("spring.application.name"); + // 周期性比对 +// compareBroadcast(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment)); +// compareRPC(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment)); + } + + @SneakyThrows + private void compareRPC(String consumerGroupName) { + log.info("current rpc consumer group is :{}", consumerGroupName); + ConsumeStats consumeStats = defaultMQAdminExt.examineConsumeStats(consumerGroupName); + if (Objects.isNull(broadcastConsumeStats)) { + broadcastConsumeStats = consumeStats; + messageQueue.putAll(calcCurrentTimes(consumerGroupName, consumeStats)); + return; + } + Map temp = calcCurrentTimes(consumerGroupName, consumeStats); + } + + private static Map calcCurrentTimes(String consumerGroupName, ConsumeStats consumeStats) { + Map temp = new HashMap<>(); + String rpcDeadLetterConsumerName = "%RETRY%" + consumerGroupName; + consumeStats.getOffsetTable().forEach((k, v) -> { + long l = v.getBrokerOffset() - v.getConsumerOffset(); + if (Objects.equals(k.getTopic(), rpcDeadLetterConsumerName)) { + // 死信队列 + temp.put(rpcDeadLetterConsumerName, l); + } else { + // 普通队列 + temp.computeIfPresent(consumerGroupName, ((k1, v1) -> v1 + l)); + } + }); + return temp; + } + + @SneakyThrows + private void compareBroadcast(String consumerGroupName) { + log.info("current broadcast consumer group is :{}", consumerGroupName); + ConsumeStats consumeStats = defaultMQAdminExt.examineConsumeStats(consumerGroupName); + if (Objects.isNull(rpcConsumeStats)) { + rpcConsumeStats = consumeStats; + messageQueue.putAll(calcCurrentTimes(consumerGroupName, consumeStats)); + return; + } + Map temp = calcCurrentTimes(consumerGroupName, consumeStats); + } + + @Override + public void start() { + if (running.compareAndSet(false, true)) { + log.info("starting workflow engine mq monitor"); + taskScheduler.scheduleWithFixedDelay(this::mqWatch, 30000); + } + } + + @Override + public void stop() { + if (running.compareAndSet(true, false)) { + log.info("destroying workflow engine mq monitor"); + taskScheduler.shutdown(); + broadcastConsumeStats = null; + rpcConsumeStats = null; + } + } + + @Override + public boolean isRunning() { + return this.running.get(); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index 112e57a32..58973d8d8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -5,6 +5,7 @@ import cn.azxo.framework.common.model.CommonResponse; import lombok.SneakyThrows; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -14,6 +15,7 @@ import java.util.HashMap; import java.util.Map; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; +import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; /** * Workflow Engine Starter MessageQueue Monitor Controller @@ -22,35 +24,38 @@ import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_E * @since 2024/6/6 10:04 */ @RestController -@RequestMapping("/web/we/starter") +@RequestMapping("/web/we/s") public class WorkflowEngineStarterMQMonitorController { @Resource private WorkflowEngineStarterProperties starterProperties; @Resource private DefaultMQAdminExt defaultMQAdminExt; + @Resource + private Environment environment; + @Value("${spring.application.name}") + private String applicationName; @Value("${spring.profiles.active}") private String activeProfile; + public static String BROADCAST_CONSUMER_GROUP = "GID_%s_workflow_engine_%s_consumer"; + public static String RPC_RETRY_CONSUMER_GROUP = "GID_%s_workflow_engine_starter_%s_consumer"; @SneakyThrows - @GetMapping("/monitor") + @GetMapping("/m") public CommonResponse> monitor() { String topic = DEFAULT_EVENT + activeProfile; - String broadcastConsumerGroup = ""; Map result = new HashMap<>(); + + String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); + result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment))); + result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment))); + result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); - result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); - System.getProperty(""); - if (starterProperties.getJoinContainerGroup()) { - } - result.put("gid_senna", defaultMQAdminExt.examineConsumeStats("GID_senna_workflow_engine_debugging_consumer")); - result.put("gid_senna_starter", defaultMQAdminExt.examineConsumeStats("GID_senna_workflow_engine_starter_debugging_consumer")); - defaultMQAdminExt.examineTopicConfig(System.getProperty("rocketmq.name-server"), "topic_workflow_engine_dev"); return CommonResponse.success(result); } } From ada8eaa5b8bb6bb80f65d0048fc34385e651a4a4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:55:11 +0800 Subject: [PATCH 098/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20workflow-auto-gen=20=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5ebad126a..fdbbe3826 100644 --- a/pom.xml +++ b/pom.xml @@ -136,11 +136,6 @@ mapstruct-processor ${mapstruct.version} - From 48dad4b55aad8e8a055a128b6813848b1eb0f539 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 15:55:18 +0800 Subject: [PATCH 099/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20workflow-auto-gen=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-auto-gen/pom.xml | 29 ---- .../generate/BaseCodeGenProcessor.java | 16 --- .../workflow/generate/CodeGenProcessor.java | 31 ----- .../generate/CodeGenProcessorRegistry.java | 43 ------ .../axzo/workflow/generate/GenCodeInfo.java | 68 ---------- .../generate/GenJavaSourceFileUtils.java | 45 ------ .../generate/GenServiceProcessor.java | 96 ------------- .../generate/ProcessingEnvironmentHolder.java | 17 --- .../WorkflowExposeApiGenProcessor.java | 128 ------------------ .../generate/annotition/GenService.java | 21 --- .../generate/annotition/Management.java | 10 -- .../javax.annotation.processing.Processor | 1 - 12 files changed, 505 deletions(-) delete mode 100644 workflow-auto-gen/pom.xml delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java delete mode 100644 workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java delete mode 100644 workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/workflow-auto-gen/pom.xml b/workflow-auto-gen/pom.xml deleted file mode 100644 index d5c2eaa66..000000000 --- a/workflow-auto-gen/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 4.0.0 - - cn.axzo.workflow - workflow-engine - ${revision} - - - workflow-auto-gen - jar - Workflow Auto Gen - - - - com.google.auto.service - auto-service - 1.1.1 - - - com.squareup - javapoet - 1.13.0 - - - - \ No newline at end of file diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java deleted file mode 100644 index 114504300..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/BaseCodeGenProcessor.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.axzo.workflow.generate; - -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.TypeElement; - -public abstract class BaseCodeGenProcessor implements CodeGenProcessor { - - public static final String PREFIX = "Base"; - - @Override - public GenCodeInfo generate(TypeElement typeElement, RoundEnvironment roundEnvironment) - throws Exception { - //添加其他逻辑扩展 - return null; - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java deleted file mode 100644 index 5b67d4e88..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.axzo.workflow.generate; - -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.TypeElement; -import java.lang.annotation.Annotation; - -public interface CodeGenProcessor { - /** - * 需要解析的类上的注解 - * - * @return - */ - Class getAnnotation(); - - /** - * 获取生成的包名 - * - * @param typeElement - * @return - */ - String generatePackage(TypeElement typeElement); - - /** - * 代码生成逻辑. - * - * @param typeElement - * @param roundEnvironment - * @throws Exception - */ - GenCodeInfo generate(TypeElement typeElement, RoundEnvironment roundEnvironment) throws Exception; -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java deleted file mode 100644 index f91adfed1..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/CodeGenProcessorRegistry.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.axzo.workflow.generate; - -import com.google.common.collect.Maps; - -import java.lang.annotation.Annotation; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; - -public class CodeGenProcessorRegistry { - private static Map PROCESSORS; - - private CodeGenProcessorRegistry() { - throw new UnsupportedOperationException(); - } - - /** - * 注解处理器要处理的注解集合 - * - * @return - */ - public static Set getSupportedAnnotations() { - return PROCESSORS.keySet(); - } - - public static CodeGenProcessor find(String annotationClassName) { - return PROCESSORS.get(annotationClassName); - } - - /** - * spi 加载所有的processor - * - */ - public static void initProcessors() { - final Map map = Maps.newLinkedHashMap(); - ServiceLoader processors = ServiceLoader.load(CodeGenProcessor.class, CodeGenProcessor.class.getClassLoader()); - for (CodeGenProcessor next : processors) { - Class annotation = next.getAnnotation(); - map.put(annotation.getName(), next); - } - PROCESSORS = map; - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java deleted file mode 100644 index 0a758a558..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenCodeInfo.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.axzo.workflow.generate; - -import com.squareup.javapoet.TypeSpec; - -public class GenCodeInfo { - private final TypeSpec typeSpec; - private final String sourcePath; - private final String packageName; - private final String className; - - public static GenCodeInfoBuilder builder() { - return new GenCodeInfoBuilder(); - } - - public TypeSpec getTypeSpec() { - return typeSpec; - } - - public String getSourcePath() { - return sourcePath; - } - - public String getPackageName() { - return packageName; - } - - public String getClassName() { - return className; - } - - private GenCodeInfo(GenCodeInfoBuilder builder) { - this.typeSpec = builder.typeSpec; - this.sourcePath = builder.sourcePath; - this.packageName = builder.packageName; - this.className = builder.className; - } - - public static class GenCodeInfoBuilder { - private TypeSpec typeSpec; - private String sourcePath; - private String packageName; - private String className; - - public GenCodeInfoBuilder typeSpec(TypeSpec typeSpec) { - this.typeSpec = typeSpec; - return this; - } - - public GenCodeInfoBuilder sourcePath(String sourcePath) { - this.sourcePath = sourcePath; - return this; - } - - public GenCodeInfoBuilder packageName(String packageName) { - this.packageName = packageName; - return this; - } - - public GenCodeInfoBuilder className(String className) { - this.className = className; - return this; - } - - public GenCodeInfo build() { - return new GenCodeInfo(this); - } - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java deleted file mode 100644 index 6d13d4e8e..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenJavaSourceFileUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.axzo.workflow.generate; - -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.TypeSpec; - -import javax.lang.model.element.Modifier; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -public class GenJavaSourceFileUtils { - - public static void genJavaSourceFile(String pathStr, String packageName, String className, List methodSpecs) { - TypeSpec typeSpec = TypeSpec - .interfaceBuilder(className) - .addModifiers(Modifier.PUBLIC) - .addMethods(methodSpecs) - .build(); - JavaFile javaFile = JavaFile.builder(packageName, typeSpec) - .addFileComment("--auto generated by workflow auto-gen plugin--") - .build(); - String javaFileName = typeSpec.name + ".java"; - try { - Path path = Paths.get(pathStr); - File packageFolder = new File(path.toFile().getAbsolutePath()); - if (!packageFolder.exists()) { - System.out.println("package not exists:" + path); - return; - } - String javaFilePath = path.toFile().getAbsolutePath() + File.separator + javaFileName; - System.out.println("name:" + javaFilePath); - File sourceFile = new File(javaFilePath); - if (!sourceFile.exists()) { - javaFile.writeTo(packageFolder); - } else { - javaFile.writeTo(packageFolder); - } - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java deleted file mode 100644 index 2d4a90603..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/GenServiceProcessor.java +++ /dev/null @@ -1,96 +0,0 @@ -package cn.axzo.workflow.generate; - -import cn.axzo.workflow.generate.annotition.GenService; -import cn.axzo.workflow.generate.annotition.Management; -import com.google.auto.service.AutoService; -import com.squareup.javapoet.AnnotationSpec; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; -import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; - -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.List; - -@AutoService(CodeGenProcessor.class) -public class GenServiceProcessor extends BaseCodeGenProcessor { - - @Override - public Class getAnnotation() { - return GenService.class; - } - - @Override - public String generatePackage(TypeElement typeElement) { - return typeElement.getAnnotation(GenService.class).genPkgName(); - } - - @Override - public GenCodeInfo generate(TypeElement typeElement, RoundEnvironment roundEnvironment) throws Exception { - String genPkgName = typeElement.getAnnotation(GenService.class).genPkgName(); - String sourcePath = typeElement.getAnnotation(GenService.class).genSourcePath(); - String genClassName = typeElement.getAnnotation(GenService.class).genClassName(); - List enclosedElements = typeElement.getEnclosedElements(); - TypeSpec.Builder targetTypeSpec = TypeSpec.interfaceBuilder(genClassName) - .addModifiers(typeElement.getModifiers().toArray(new Modifier[]{})); - for (Element enclosedElement : enclosedElements) { - if (enclosedElement instanceof ExecutableElement) { - ExecutableElement executableElement = (ExecutableElement) enclosedElement; - List annotationMirrors = executableElement.getAnnotationMirrors(); - boolean add = true; - for (AnnotationMirror annotationMirror : annotationMirrors) { - if (annotationMirror.getAnnotationType().toString().equals(Management.class.getName())) { - add = false; - } - } - if (add) { - List parameterSpecs = new ArrayList<>(); - for (VariableElement variableElement : executableElement.getParameters()) { - ParameterSpec parameterSpec = ParameterSpec.get(variableElement); - List paramAnnotations = variableElement.getAnnotationMirrors(); - if (paramAnnotations != null && !paramAnnotations.isEmpty()) { - List annotationSpecs = new ArrayList<>(); - for (AnnotationMirror annotation : paramAnnotations) { - annotationSpecs.add(AnnotationSpec.get(annotation)); - } - parameterSpec = parameterSpec.toBuilder().addAnnotations(annotationSpecs).build(); - } - parameterSpecs.add(parameterSpec); - } - List annotationSpecs = new ArrayList<>(); - for (AnnotationMirror annotationMirror : annotationMirrors) { - annotationSpecs.add(AnnotationSpec.get(annotationMirror)); - } - List exceptions = new ArrayList<>(); - List thrownTypes = executableElement.getThrownTypes(); - for (TypeMirror typeMirror : thrownTypes) { - exceptions.add(TypeName.get(typeMirror)); - } - MethodSpec main = MethodSpec.methodBuilder(enclosedElement.getSimpleName().toString()) - .addModifiers(enclosedElement.getModifiers()) - .returns(TypeName.get(executableElement.getReturnType())) - .addParameters(parameterSpecs) - .addAnnotations(annotationSpecs) - .addExceptions(exceptions) - .build(); - targetTypeSpec.addMethod(main); - } - } - } - return GenCodeInfo.builder() - .className(genClassName) - .packageName(genPkgName) - .sourcePath(sourcePath) - .typeSpec(targetTypeSpec.build()) - .build(); - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java deleted file mode 100644 index 26f2e1d40..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/ProcessingEnvironmentHolder.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.axzo.workflow.generate; - -import javax.annotation.processing.ProcessingEnvironment; - -public final class ProcessingEnvironmentHolder { - - public static final ThreadLocal environment = new ThreadLocal<>(); - - - public static void setEnvironment(ProcessingEnvironment pe) { - environment.set(pe); - } - - public static ProcessingEnvironment getEnvironment() { - return environment.get(); - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java deleted file mode 100644 index 18228e7c7..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/WorkflowExposeApiGenProcessor.java +++ /dev/null @@ -1,128 +0,0 @@ -package cn.axzo.workflow.generate; - -import com.google.auto.service.AutoService; -import com.squareup.javapoet.MethodSpec; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.ElementFilter; -import javax.tools.Diagnostic; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -@AutoService(Processor.class) -public class WorkflowExposeApiGenProcessor extends AbstractProcessor { - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - List genCodeInfos = new ArrayList<>(); - annotations.forEach(an -> { - Set typeElements = roundEnv.getElementsAnnotatedWith(an); - Set types = ElementFilter.typesIn(typeElements); - for (TypeElement typeElement : types) { - CodeGenProcessor codeGenProcessor = CodeGenProcessorRegistry.find(an.getQualifiedName().toString()); - try { - GenCodeInfo generate = codeGenProcessor.generate(typeElement, roundEnv); - genCodeInfos.add(generate); - } catch (Exception e) { - ProcessingEnvironmentHolder.getEnvironment().getMessager().printMessage(Diagnostic.Kind.ERROR, "代码生成异常:" + e.getMessage()); - } - } - }); - if (!genCodeInfos.isEmpty()) { - Map, List> apiGenMap = new HashMap<>(); - //进行分组 - for (GenCodeInfo genCodeInfo : genCodeInfos) { - Triplet triplet = Triplet.of(genCodeInfo.getSourcePath(), genCodeInfo.getPackageName(), genCodeInfo.getClassName()); - List codeInfos = apiGenMap.computeIfAbsent(triplet, k -> new ArrayList<>()); - codeInfos.add(genCodeInfo); - } - for (Map.Entry, List> entry : apiGenMap.entrySet()) { - Triplet triplet = entry.getKey(); - List methodSpecs = new ArrayList<>(); - List infos = entry.getValue(); - for (GenCodeInfo genCodeInfo : infos) { - methodSpecs.addAll(genCodeInfo.getTypeSpec().methodSpecs); - } - GenJavaSourceFileUtils.genJavaSourceFile(triplet.getFirst(), triplet.getSecond(), triplet.getThird(), methodSpecs); - } - } - return false; - } - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - ProcessingEnvironmentHolder.setEnvironment(processingEnv); - CodeGenProcessorRegistry.initProcessors(); - } - - @Override - public Set getSupportedAnnotationTypes() { - return CodeGenProcessorRegistry.getSupportedAnnotations(); - } - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - public static final class Triplet { - private final T first; - private final U second; - private final V third; - - public Triplet(T first, U second, V third) { - this.first = first; - this.second = second; - this.third = third; - } - - public T getFirst() { - return first; - } - - public U getSecond() { - return second; - } - - public V getThird() { - return third; - } - - @Override - public String toString() { - return "Triplet{" + - "first=" + first + - ", second=" + second + - ", third=" + third + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Triplet triplet = (Triplet) o; - return Objects.equals(first, triplet.first) && Objects.equals(second, triplet.second) && Objects.equals(third, triplet.third); - } - - @Override - public int hashCode() { - return Objects.hash(first, second, third); - } - - public static Triplet of(T first, U second, V third) { - return new Triplet<>(first, second, third); - } - } -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java deleted file mode 100644 index 2b7e414ac..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/GenService.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.axzo.workflow.generate.annotition; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface GenService { - - String genPkgName(); - - String genSourcePath() default "workflow-engine-spring-boot-starter/src/main/java"; - - String genClassName() default "WorkflowCoreService_Gen"; - - boolean overrideSource() default false; -} diff --git a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java b/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java deleted file mode 100644 index 72de7210f..000000000 --- a/workflow-auto-gen/src/main/java/cn/axzo/workflow/generate/annotition/Management.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.axzo.workflow.generate.annotition; - -/** - * 控制接口是否调用受限,标记了注解的方法,表示受控,不允许暴露给客户端使用 - * - * @author wangli - * @since 2024/5/22 10:43 - */ -public @interface Management { -} diff --git a/workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor deleted file mode 100644 index ddef324fa..000000000 --- a/workflow-auto-gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ /dev/null @@ -1 +0,0 @@ -cn.axzo.workflow.generate.WorkflowExposeApiGenProcessor \ No newline at end of file From 96764e7bc6c7a99fdac5902158af3bc55565ed7d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 16:00:05 +0800 Subject: [PATCH 100/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E9=BB=98=E8=AE=A4=E7=9A=84=20WorkflowCoreService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/starter/api/WorkflowCoreService.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 0a0899d04..287ee06e6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,22 +1,19 @@ package cn.axzo.workflow.starter.api; -import org.springframework.cloud.openfeign.FeignClient; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import cn.axzo.workflow.common.util.ThreadUtil; - import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; - import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; - import javax.validation.constraints.NotBlank; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; @@ -38,7 +35,6 @@ import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PutMapping; - import javax.annotation.Nullable; import javax.validation.constraints.NotNull; import java.util.List; @@ -57,7 +53,6 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstance import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; - import javax.validation.constraints.NotEmpty; /** From 74e5149f8fad02c5ba627f238139f2247222282e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 17:57:21 +0800 Subject: [PATCH 101/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=8E=9F=20API=20=E4=B8=AD=20FeignClient=20=E7=9A=84?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=86=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/config/WorkflowEngineClientAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowEngineClientAutoConfiguration.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowEngineClientAutoConfiguration.java index 18029b184..b27854cc8 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowEngineClientAutoConfiguration.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/config/WorkflowEngineClientAutoConfiguration.java @@ -31,7 +31,7 @@ import java.util.regex.Pattern; * @Date: 2022/9/17 * @Description: */ -@EnableFeignClients(basePackages = {"cn.axzo.workflow.client.feign"}) +//@EnableFeignClients(basePackages = {"cn.axzo.workflow.client.feign"}) @Configuration(proxyBeanMethods = false) @Slf4j public class WorkflowEngineClientAutoConfiguration { From 38333aaec2a352e62f25865640af73239a4bb69b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 18:02:26 +0800 Subject: [PATCH 102/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20pom=EF=BC=8C=E6=96=B9=E4=BE=BF=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=96=B9=E8=83=BD=E6=AD=A3=E7=A1=AE=E7=9A=84=E4=BC=A0=E9=80=92?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index b9be7e34a..d4ad16469 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -16,8 +16,9 @@ true - cn.axzo.workflow + ${project.groupId} workflow-engine-api + ${project.version} cn.axzo.framework.rocketmq From 2b09d2e3103a147ad1aafb11130b78daefe3f72b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 18:13:20 +0800 Subject: [PATCH 103/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=BA?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20default=20=E8=AE=BF=E9=97=AE=E4=BF=AE=E9=A5=B0?= =?UTF-8?q?=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MessageNotificationEventHandler.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java index 3fc18b031..8a4528bbe 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java @@ -16,47 +16,55 @@ public interface MessageNotificationEventHandler extends Ordered { * * @param messagePushDTO */ - void pushNotice(MessagePushDTO messagePushDTO); + default void pushNotice(MessagePushDTO messagePushDTO) { + } /** * 待办推送 * * @param messagePushDTO */ - void pushPending(MessagePushDTO messagePushDTO); + default void pushPending(MessagePushDTO messagePushDTO) { + } /** * 完成待办 * * @param messagePushDTO */ - void completePending(MessagePushDTO messagePushDTO); + default void completePending(MessagePushDTO messagePushDTO) { + } /** * 审批失败,恢复待办 * * @param messagePushDTO */ - void rollbackPending(MessagePushDTO messagePushDTO); + default void rollbackPending(MessagePushDTO messagePushDTO) { + } /** * 抄送流程 * * @param messagePushDTO */ - void carbonCopy(MessagePushDTO messagePushDTO); + default void carbonCopy(MessagePushDTO messagePushDTO) { + } /** * 完成抄送 * * @param messagePushDTO */ - void carbonCopyComplete(MessagePushDTO messagePushDTO); + default void carbonCopyComplete(MessagePushDTO messagePushDTO) { + } /** * 短信推送 * * @param messagePushDTO */ - void pushSms(MessagePushDTO messagePushDTO); + default void pushSms(MessagePushDTO messagePushDTO) { + } + } From 2a6306a2ff6bec342a423f519c71f58c62044d45 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 18:19:07 +0800 Subject: [PATCH 104/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=BA?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20default=20=E8=AE=BF=E9=97=AE=E4=BF=AE=E9=A5=B0?= =?UTF-8?q?=E7=AC=A6,=20=E6=8E=A5=E5=85=A5=E6=96=B9=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E6=8C=89=E9=9C=80=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/ProcessActivityEventHandler.java | 13 +++++++++---- .../handler/ProcessInstanceEventHandler.java | 18 ++++++++++++------ .../handler/ProcessTaskEventHandler.java | 12 ++++++++---- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java index 53b1262f2..f6f62b9e8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java @@ -10,6 +10,7 @@ import org.springframework.core.Ordered; *

  *  OMS -> 审批流程 -> 审批配置台 -> 流程配置
  * 
+ * * @author wangli * @since 2024/5/27 16:25 */ @@ -20,26 +21,30 @@ public interface ProcessActivityEventHandler extends Ordered { * * @param activityDTO 入参 */ - void onStart(ProcessActivityDTO activityDTO); + default void onStart(ProcessActivityDTO activityDTO) { + } /** * 节点等待业务指定审批人 * * @param activityDTO 入参 */ - void onWaitAssignee(ProcessActivityDTO activityDTO); + default void onWaitAssignee(ProcessActivityDTO activityDTO) { + } /** * 节点已完成 * * @param activityDTO 入参 */ - void onTake(ProcessActivityDTO activityDTO); + default void onTake(ProcessActivityDTO activityDTO) { + } /** * 节点已取消 * * @param activityDTO 入参 */ - void onEnd(ProcessActivityDTO activityDTO); + default void onEnd(ProcessActivityDTO activityDTO) { + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java index 5aadd8b63..a0d9d33bc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java @@ -18,14 +18,16 @@ public interface ProcessInstanceEventHandler extends Ordered { * * @param processInstanceDTO */ - void onCreated(ProcessInstanceDTO instanceDTO); + default void onCreated(ProcessInstanceDTO instanceDTO) { + } /** * 流程实例开始运行后回调 * * @param processInstanceDTO */ - void onStarted(ProcessInstanceDTO instanceDTO); + default void onStarted(ProcessInstanceDTO instanceDTO) { + } /** * 流程实例运行完成(通过)后回调 @@ -34,7 +36,8 @@ public interface ProcessInstanceEventHandler extends Ordered { * * @param instanceDTO */ - void onCompleted(ProcessInstanceDTO instanceDTO); + default void onCompleted(ProcessInstanceDTO instanceDTO) { + } /** * 流程实例被“撤回”后回调 @@ -43,7 +46,8 @@ public interface ProcessInstanceEventHandler extends Ordered { * * @param instanceDTO */ - void onCancelled(ProcessInstanceDTO instanceDTO); + default void onCancelled(ProcessInstanceDTO instanceDTO) { + } /** * 流程实例被“驳回”后回调 @@ -52,7 +56,8 @@ public interface ProcessInstanceEventHandler extends Ordered { * * @param instanceDTO */ - void onRejected(ProcessInstanceDTO instanceDTO); + default void onRejected(ProcessInstanceDTO instanceDTO) { + } /** * 流程实例被中止后回调 @@ -61,5 +66,6 @@ public interface ProcessInstanceEventHandler extends Ordered { * * @param instanceDTO */ - void onAborted(ProcessInstanceDTO instanceDTO); + default void onAborted(ProcessInstanceDTO instanceDTO) { + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java index 033e4c2e8..220eb2da9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java @@ -16,24 +16,28 @@ public interface ProcessTaskEventHandler extends Ordered { /** * 用户任务已指派审核人 */ - void onAssigned(ProcessTaskDTO taskDTO); + default void onAssigned(ProcessTaskDTO taskDTO) { + } /** * 用户任务已创建,未指派审核人 */ - void onCreated(ProcessTaskDTO taskDTO); + default void onCreated(ProcessTaskDTO taskDTO) { + } /** * 用户任务已通过 *

* 仅审核通过一个用户任务时触发, 如果任务是驳回了, 则直接走实例撤回事件 */ - void onCompleted(ProcessTaskDTO taskDTO); + default void onCompleted(ProcessTaskDTO taskDTO) { + } /** * 用户任务已删除 *

* 删除不代表驳回或拒绝,因为通过也会走该事件 */ - void onDeleted(ProcessTaskDTO taskDTO); + default void onDeleted(ProcessTaskDTO taskDTO) { + } } From 933768dfe5d62c1317cce4e4d069a7994b6faa09 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 19:56:01 +0800 Subject: [PATCH 105/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=97=A5=E5=BF=97=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 5 +++++ .../starter/StarterBroadcastMQConfiguration.java | 7 +++---- .../starter/StarterRPCInvokeMQConfiguration.java | 2 +- ...KeyInner.java => InnerFilterDefinitionKey.java} | 10 +++++----- .../mq/broadcast/filter/InnerFilterExtension.java | 14 +------------- .../broadcast/filter/InnerFilterMQOwnerShip.java | 12 +++++++++--- 6 files changed, 24 insertions(+), 26 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/{InnerFilterDefinitionKeyInner.java => InnerFilterDefinitionKey.java} (69%) diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index d4ad16469..012ce6cf9 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -15,6 +15,11 @@ spring-boot-starter true + + org.springframework.boot + spring-boot-configuration-processor + true + ${project.groupId} workflow-engine-api diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index effbf6545..f56712e9b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -10,7 +10,7 @@ import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentConditio import cn.axzo.workflow.starter.handler.filter.global.BroadcastMessageQueueFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; -import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKeyInner; +import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKey; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; @@ -33,7 +33,6 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; -import java.util.Objects; import java.util.function.Consumer; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; @@ -100,7 +99,7 @@ public class StarterBroadcastMQConfiguration { public void onMessage(MessageExt message) { for (InnerMessageQueueHandleBeforeFilter filter : filters) { if (filter.doFilter(message)) { - log.info("message has been filtered"); + log.info("【{}】message has been filtered, messageId: {}", this.getClass().getSimpleName(), message.getMsgId()); return; } } @@ -111,7 +110,7 @@ public class StarterBroadcastMQConfiguration { public void afterPropertiesSet() { this.filters = ImmutableList.of( new InnerFilterMQOwnerShip(starterProperties, applicationName), - new InnerFilterDefinitionKeyInner(starterProperties), + new InnerFilterDefinitionKey(starterProperties), new InnerFilterExtension(businessFilterProvider)); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index e4167cbdc..171a0a84b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -179,7 +179,7 @@ public class StarterRPCInvokeMQConfiguration { @Override public void onMessage(MessageExt message) { if (filter.doFilter(message)) { - log.info("message has been filtered"); + log.info("【{}】message has been filtered, messageId: {}", this.getClass().getSimpleName(), message.getMsgId()); return; } super.onEvent(message, workflowEngineStarterEventConsumer); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java similarity index 69% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java index 8a0554f07..c13d1ea00 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKeyInner.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java @@ -17,11 +17,11 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCES * @author wangli * @since 2024/6/4 17:06 */ -public class InnerFilterDefinitionKeyInner implements InnerMessageQueueHandleBeforeFilter { - private final Logger log = LoggerFactory.getLogger(InnerFilterDefinitionKeyInner.class); +public class InnerFilterDefinitionKey implements InnerMessageQueueHandleBeforeFilter { + private final Logger log = LoggerFactory.getLogger(InnerFilterDefinitionKey.class); private final WorkflowEngineStarterProperties properties; - public InnerFilterDefinitionKeyInner(WorkflowEngineStarterProperties properties) { + public InnerFilterDefinitionKey(WorkflowEngineStarterProperties properties) { this.properties = properties; } @@ -31,7 +31,7 @@ public class InnerFilterDefinitionKeyInner implements InnerMessageQueueHandleBef return false; } if (CollectionUtils.isEmpty(properties.getBroadcast().getFilterProcessDefinitionKeys())) { - log.warn("Your system has the filter process-definition-key enabled, but `BroadcastListenerConfigurationProperties.filterProcessDefinitionKeys` is empty"); + log.warn("【{}】Your system has the filter process-definition-key enabled, but `BroadcastListenerConfigurationProperties.filterProcessDefinitionKeys` is empty", this.getClass().getSimpleName()); return false; } Map headers = message.getProperties(); @@ -39,7 +39,7 @@ public class InnerFilterDefinitionKeyInner implements InnerMessageQueueHandleBef if (properties.getBroadcast().getFilterProcessDefinitionKeys().contains(processDefinitionKey)) { return false; } - log.info("The broadcast message does not belong to the key of interest, will be ignored. messageId: {}, message process-definition-key: {}", message.getMsgId(), processDefinitionKey); + log.debug("【{}】The broadcast message does not belong to the key of interest, will be ignored. messageId: {}, message process-definition-key: {}", this.getClass().getSimpleName(), message.getMsgId(), processDefinitionKey); return true; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java index 2056ae6dc..83647d8b4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java @@ -36,7 +36,7 @@ public class InnerFilterExtension implements InnerMessageQueueHandleBeforeFilter @Override public boolean doFilter(MessageExt message) { if (businessFilters.isEmpty()) { - log.debug("business filter is empty"); + log.debug("【{}】business filter is empty", this.getClass().getSimpleName()); return false; } for (BroadcastMessageQueueFilter businessFilter : businessFilters) { @@ -45,18 +45,6 @@ public class InnerFilterExtension implements InnerMessageQueueHandleBeforeFilter } } return false; - - -// for (BroadcastMessageQueueFilter businessFilter : businessFilters) { -// Object payload = new String(message.getBody(), UTF_8); -// Class typeClass = getParameterizedTypeClass(businessFilter); -// if(Objects.nonNull(typeClass)) { -// payload = JSON.parseObject((String) payload, typeClass); -// } -// if (businessFilter.doFilter(message, payload)) { -// return true; -// } -// } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java index 3f105d98a..a20002965 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java @@ -35,10 +35,16 @@ public class InnerFilterMQOwnerShip implements InnerMessageQueueHandleBeforeFilt Map headers = message.getProperties(); String mqOwnerShip = headers.getOrDefault(MQ_OWNERSHIP_APPLICATION, null); - if (StringUtils.hasText(mqOwnerShip) && properties.getBroadcast().getFilterApplicationNames().contains(mqOwnerShip)) { + if (!StringUtils.hasText(mqOwnerShip)) { + log.debug("【{}】The broadcast message does not attribute the message, will not be ignored. messageId: {}", this.getClass().getSimpleName(), message.getMsgId()); return false; + } else { + if (properties.getBroadcast().getFilterApplicationNames().contains(mqOwnerShip)) { + return false; + } else { + log.debug("【{}】The broadcast message does not attribute the message, will be ignored. messageId: {}, mq-ownership-application: {}", this.getClass().getSimpleName(), message.getMsgId(), mqOwnerShip); + return true; + } } - log.info("The broadcast message does not attribute the message, will be ignored. messageId: {}, mq-ownership-application: {}", message.getMsgId(), mqOwnerShip); - return true; } } From 17394958930a50692b71ee26afed980514c81575 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 20:40:33 +0800 Subject: [PATCH 106/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20properties=20=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=20metadata.json=20=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 ++- workflow-engine-spring-boot-starter/pom.xml | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fdbbe3826..68fcd93d4 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index 012ce6cf9..bd8421bb7 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -36,4 +36,15 @@ 4.9.1 + + + + org.apache.maven.plugins + maven-compiler-plugin + + none + + + + From a8d07ad27d7ae0eced6aef3d7c1afc133a92e6b2 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 12 Jun 2024 20:50:51 +0800 Subject: [PATCH 107/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20lombok=20=E7=9A=84=E6=B3=A8=E8=A7=A3=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E7=BC=96=E8=AF=91=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java | 7 ++----- .../console/WorkflowEngineStarterMQMonitorController.java | 3 +-- .../consumer/WorkflowEngineStarterRetryEventListener.java | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 65d98396a..0acaccaec 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -46,7 +46,6 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { return taskScheduler; } - @SneakyThrows public void mqWatch() { log.info("time is :{}", System.currentTimeMillis()); String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); @@ -56,8 +55,7 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { // compareRPC(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment)); } - @SneakyThrows - private void compareRPC(String consumerGroupName) { + private void compareRPC(String consumerGroupName) throws Exception { log.info("current rpc consumer group is :{}", consumerGroupName); ConsumeStats consumeStats = defaultMQAdminExt.examineConsumeStats(consumerGroupName); if (Objects.isNull(broadcastConsumeStats)) { @@ -84,8 +82,7 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { return temp; } - @SneakyThrows - private void compareBroadcast(String consumerGroupName) { + private void compareBroadcast(String consumerGroupName) throws Exception { log.info("current broadcast consumer group is :{}", consumerGroupName); ConsumeStats consumeStats = defaultMQAdminExt.examineConsumeStats(consumerGroupName); if (Objects.isNull(rpcConsumeStats)) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index 58973d8d8..b1367687b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -39,9 +39,8 @@ public class WorkflowEngineStarterMQMonitorController { public static String BROADCAST_CONSUMER_GROUP = "GID_%s_workflow_engine_%s_consumer"; public static String RPC_RETRY_CONSUMER_GROUP = "GID_%s_workflow_engine_starter_%s_consumer"; - @SneakyThrows @GetMapping("/m") - public CommonResponse> monitor() { + public CommonResponse> monitor() throws Exception { String topic = DEFAULT_EVENT + activeProfile; Map result = new HashMap<>(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 1eac34b65..7414db959 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -111,7 +111,6 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In return expression; } - @SneakyThrows @Override public void onEvent(Event event, EventConsumer.Context context) { log.info("WorkflowEngineClientRetryEventListener onEvent: {}", event.toPrettyJsonString()); @@ -139,7 +138,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In log.error("Event Invoke Exception: {}", cause.getMessage(), cause); if (cause instanceof ConnectException) { // 而只有当网络异常时, 利用 RocketMQ 的重试机制 - throw cause; + throw new RuntimeException(cause); } } } From f5e9ea90daaad891e8266e734f2fd2e8101ca654 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 09:31:32 +0800 Subject: [PATCH 108/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20configuration-metadata.json=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...itional-spring-configuration-metadata.json | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..f6d6adbfd --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,84 @@ +{ + "groups": [ + { + "name": "workflow.engine.starter", + "type": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties", + "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties" + }, + { + "name": "workflow.engine.starter.broadcast", + "type": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties", + "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties", + "sourceMethod": "getBroadcast()" + } + ], + "properties": [ + { + "name": "workflow.engine.starter.broadcast.enable-filter-application-name", + "type": "java.lang.Boolean", + "description": "是否开启根据应用名过滤 MQ 事件", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.enable-filter-definition-key", + "type": "java.lang.Boolean", + "description": "是否开启根据业务 ID 集合过滤 MQ 事件", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.fail-handle-type", + "type": "cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum", + "description": "失败处理策略:

 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略) 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 <\/pre>",
+      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast.filter-application-names",
+      "type": "java.util.Set",
+      "description": "仅过滤这些应用名称创建的流程",
+      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast.filter-process-definition-keys",
+      "type": "java.util.Set",
+      "description": "过滤出 MQ 事件中包含这些业务 ID 的事件 

只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效

注意: 如果 enableFilterDefinitionKey = true,但该属性集合为空, 将不会过滤<\/strong>任何消息", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.num-of-retries", + "type": "java.lang.Integer", + "description": "自动重试次数", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.wait-increase-factor", + "type": "java.lang.Integer", + "description": "重试累乘因子, 意味多次重试时,每次重试间隔为 waitTimeInMs * waitIncreaseFactor 毫秒", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.wait-time-in-ms", + "type": "java.lang.Integer", + "description": "初始等待时间,单位:毫秒", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.invoke-mode", + "type": "cn.axzo.workflow.common.enums.RpcInvokeModeEnum", + "description": "WorkflowCoreService 类中所有方法未标记{@link InvokeMode}注解的方法调用时, 默认采用的模式

 如果是同步调用,则直接通过普通 FeignClient 进行调用, 否则将通过 MQ 将 RPC 调用进行解耦 <\/pre> 

如果方法上有{@link InvokeMode}注解, 则以注解上的模式优先, 如果还想覆盖注解中的模式, 则可以通过 {@link WorkflowCoreService#sync()}或{@link WorkflowCoreService#async()}方法进行覆盖", + "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties" + }, + { + "name": "workflow.engine.starter.join-container-group", + "type": "java.lang.Boolean", + "description": "

该参数只针对非<\/strong>容器环境生效<\/h3> 本地启动时,是否将本地的 MQ 消费者加入集群消费组
 默认 false, 本地启动应用时, 将创建消息组名称中含有\"debugging\"的消费组. 否则, 本地启动应用时, 消费者将加入容器环境, 进行集群消费. <\/pre>",
+      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
+    },
+    {
+      "name": "workflow.engine.starter.manageable",
+      "type": "java.lang.Boolean",
+      "description": "是否可管理",
+      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
+    }
+  ],
+  "hints": []
+}

From bca567dba5bc72ca1ebbe158bc7755175a67128f Mon Sep 17 00:00:00 2001
From: wangli <274027703@qq.com>
Date: Thu, 13 Jun 2024 09:51:05 +0800
Subject: [PATCH 109/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B7=BB?=
 =?UTF-8?q?=E5=8A=A0=20configuration-metadata.json=20=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../spring-configuration-metadata.json        | 84 +++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json

diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json
new file mode 100644
index 000000000..f6d6adbfd
--- /dev/null
+++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,84 @@
+{
+  "groups": [
+    {
+      "name": "workflow.engine.starter",
+      "type": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties",
+      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast",
+      "type": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties",
+      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties",
+      "sourceMethod": "getBroadcast()"
+    }
+  ],
+  "properties": [
+    {
+      "name": "workflow.engine.starter.broadcast.enable-filter-application-name",
+      "type": "java.lang.Boolean",
+      "description": "是否开启根据应用名过滤 MQ 事件",
+      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast.enable-filter-definition-key",
+      "type": "java.lang.Boolean",
+      "description": "是否开启根据业务 ID 集合过滤 MQ 事件",
+      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast.fail-handle-type",
+      "type": "cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum",
+      "description": "失败处理策略: 
 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略) 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 <\/pre>",
+      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast.filter-application-names",
+      "type": "java.util.Set",
+      "description": "仅过滤这些应用名称创建的流程",
+      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
+    },
+    {
+      "name": "workflow.engine.starter.broadcast.filter-process-definition-keys",
+      "type": "java.util.Set",
+      "description": "过滤出 MQ 事件中包含这些业务 ID 的事件 

只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效

注意: 如果 enableFilterDefinitionKey = true,但该属性集合为空, 将不会过滤<\/strong>任何消息", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.num-of-retries", + "type": "java.lang.Integer", + "description": "自动重试次数", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.wait-increase-factor", + "type": "java.lang.Integer", + "description": "重试累乘因子, 意味多次重试时,每次重试间隔为 waitTimeInMs * waitIncreaseFactor 毫秒", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.broadcast.wait-time-in-ms", + "type": "java.lang.Integer", + "description": "初始等待时间,单位:毫秒", + "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" + }, + { + "name": "workflow.engine.starter.invoke-mode", + "type": "cn.axzo.workflow.common.enums.RpcInvokeModeEnum", + "description": "WorkflowCoreService 类中所有方法未标记{@link InvokeMode}注解的方法调用时, 默认采用的模式

 如果是同步调用,则直接通过普通 FeignClient 进行调用, 否则将通过 MQ 将 RPC 调用进行解耦 <\/pre> 

如果方法上有{@link InvokeMode}注解, 则以注解上的模式优先, 如果还想覆盖注解中的模式, 则可以通过 {@link WorkflowCoreService#sync()}或{@link WorkflowCoreService#async()}方法进行覆盖", + "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties" + }, + { + "name": "workflow.engine.starter.join-container-group", + "type": "java.lang.Boolean", + "description": "

该参数只针对非<\/strong>容器环境生效<\/h3> 本地启动时,是否将本地的 MQ 消费者加入集群消费组
 默认 false, 本地启动应用时, 将创建消息组名称中含有\"debugging\"的消费组. 否则, 本地启动应用时, 消费者将加入容器环境, 进行集群消费. <\/pre>",
+      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
+    },
+    {
+      "name": "workflow.engine.starter.manageable",
+      "type": "java.lang.Boolean",
+      "description": "是否可管理",
+      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
+    }
+  ],
+  "hints": []
+}

From 911b79c89f05b13d949fed9d5e32b81f822c9e30 Mon Sep 17 00:00:00 2001
From: wangli <274027703@qq.com>
Date: Thu, 13 Jun 2024 10:05:53 +0800
Subject: [PATCH 110/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=80=9A?=
 =?UTF-8?q?=E8=BF=87=E6=8F=92=E4=BB=B6=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?=
 =?UTF-8?q?=20metadata.json=20=E5=B9=B6=E6=89=93=E8=BF=9B=20jar=20?=
 =?UTF-8?q?=E5=8C=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                       |  5 ++
 workflow-engine-spring-boot-starter/pom.xml   | 11 ---
 ...itional-spring-configuration-metadata.json | 84 -------------------
 .../spring-configuration-metadata.json        | 84 -------------------
 4 files changed, 5 insertions(+), 179 deletions(-)
 delete mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
 delete mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json

diff --git a/pom.xml b/pom.xml
index 68fcd93d4..03df7489b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,6 +137,11 @@
                             mapstruct-processor
                             ${mapstruct.version}
                         
+                        
+                            org.springframework.boot
+                            spring-boot-configuration-processor
+                            ${spring.boot.version}
+                        
                     
                 
             
diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml
index bd8421bb7..012ce6cf9 100644
--- a/workflow-engine-spring-boot-starter/pom.xml
+++ b/workflow-engine-spring-boot-starter/pom.xml
@@ -36,15 +36,4 @@
             4.9.1
         
     
-    
-        
-            
-                org.apache.maven.plugins
-                maven-compiler-plugin
-                
-                    none
-                
-            
-        
-    
 
diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
deleted file mode 100644
index f6d6adbfd..000000000
--- a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
-  "groups": [
-    {
-      "name": "workflow.engine.starter",
-      "type": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast",
-      "type": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties",
-      "sourceMethod": "getBroadcast()"
-    }
-  ],
-  "properties": [
-    {
-      "name": "workflow.engine.starter.broadcast.enable-filter-application-name",
-      "type": "java.lang.Boolean",
-      "description": "是否开启根据应用名过滤 MQ 事件",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.enable-filter-definition-key",
-      "type": "java.lang.Boolean",
-      "description": "是否开启根据业务 ID 集合过滤 MQ 事件",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.fail-handle-type",
-      "type": "cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum",
-      "description": "失败处理策略: 
 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略) 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 <\/pre>",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.filter-application-names",
-      "type": "java.util.Set",
-      "description": "仅过滤这些应用名称创建的流程",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.filter-process-definition-keys",
-      "type": "java.util.Set",
-      "description": "过滤出 MQ 事件中包含这些业务 ID 的事件 

只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效

注意: 如果 enableFilterDefinitionKey = true,但该属性集合为空, 将不会过滤<\/strong>任何消息", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.broadcast.num-of-retries", - "type": "java.lang.Integer", - "description": "自动重试次数", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.broadcast.wait-increase-factor", - "type": "java.lang.Integer", - "description": "重试累乘因子, 意味多次重试时,每次重试间隔为 waitTimeInMs * waitIncreaseFactor 毫秒", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.broadcast.wait-time-in-ms", - "type": "java.lang.Integer", - "description": "初始等待时间,单位:毫秒", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.invoke-mode", - "type": "cn.axzo.workflow.common.enums.RpcInvokeModeEnum", - "description": "WorkflowCoreService 类中所有方法未标记{@link InvokeMode}注解的方法调用时, 默认采用的模式

 如果是同步调用,则直接通过普通 FeignClient 进行调用, 否则将通过 MQ 将 RPC 调用进行解耦 <\/pre> 

如果方法上有{@link InvokeMode}注解, 则以注解上的模式优先, 如果还想覆盖注解中的模式, 则可以通过 {@link WorkflowCoreService#sync()}或{@link WorkflowCoreService#async()}方法进行覆盖", - "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties" - }, - { - "name": "workflow.engine.starter.join-container-group", - "type": "java.lang.Boolean", - "description": "

该参数只针对非<\/strong>容器环境生效<\/h3> 本地启动时,是否将本地的 MQ 消费者加入集群消费组
 默认 false, 本地启动应用时, 将创建消息组名称中含有\"debugging\"的消费组. 否则, 本地启动应用时, 消费者将加入容器环境, 进行集群消费. <\/pre>",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
-    },
-    {
-      "name": "workflow.engine.starter.manageable",
-      "type": "java.lang.Boolean",
-      "description": "是否可管理",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
-    }
-  ],
-  "hints": []
-}
diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json
deleted file mode 100644
index f6d6adbfd..000000000
--- a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json
+++ /dev/null
@@ -1,84 +0,0 @@
-{
-  "groups": [
-    {
-      "name": "workflow.engine.starter",
-      "type": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast",
-      "type": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties",
-      "sourceMethod": "getBroadcast()"
-    }
-  ],
-  "properties": [
-    {
-      "name": "workflow.engine.starter.broadcast.enable-filter-application-name",
-      "type": "java.lang.Boolean",
-      "description": "是否开启根据应用名过滤 MQ 事件",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.enable-filter-definition-key",
-      "type": "java.lang.Boolean",
-      "description": "是否开启根据业务 ID 集合过滤 MQ 事件",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.fail-handle-type",
-      "type": "cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum",
-      "description": "失败处理策略: 
 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略) 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持 <\/pre>",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.filter-application-names",
-      "type": "java.util.Set",
-      "description": "仅过滤这些应用名称创建的流程",
-      "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties"
-    },
-    {
-      "name": "workflow.engine.starter.broadcast.filter-process-definition-keys",
-      "type": "java.util.Set",
-      "description": "过滤出 MQ 事件中包含这些业务 ID 的事件 

只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效

注意: 如果 enableFilterDefinitionKey = true,但该属性集合为空, 将不会过滤<\/strong>任何消息", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.broadcast.num-of-retries", - "type": "java.lang.Integer", - "description": "自动重试次数", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.broadcast.wait-increase-factor", - "type": "java.lang.Integer", - "description": "重试累乘因子, 意味多次重试时,每次重试间隔为 waitTimeInMs * waitIncreaseFactor 毫秒", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.broadcast.wait-time-in-ms", - "type": "java.lang.Integer", - "description": "初始等待时间,单位:毫秒", - "sourceType": "cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties" - }, - { - "name": "workflow.engine.starter.invoke-mode", - "type": "cn.axzo.workflow.common.enums.RpcInvokeModeEnum", - "description": "WorkflowCoreService 类中所有方法未标记{@link InvokeMode}注解的方法调用时, 默认采用的模式

 如果是同步调用,则直接通过普通 FeignClient 进行调用, 否则将通过 MQ 将 RPC 调用进行解耦 <\/pre> 

如果方法上有{@link InvokeMode}注解, 则以注解上的模式优先, 如果还想覆盖注解中的模式, 则可以通过 {@link WorkflowCoreService#sync()}或{@link WorkflowCoreService#async()}方法进行覆盖", - "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties" - }, - { - "name": "workflow.engine.starter.join-container-group", - "type": "java.lang.Boolean", - "description": "

该参数只针对非<\/strong>容器环境生效<\/h3> 本地启动时,是否将本地的 MQ 消费者加入集群消费组
 默认 false, 本地启动应用时, 将创建消息组名称中含有\"debugging\"的消费组. 否则, 本地启动应用时, 消费者将加入容器环境, 进行集群消费. <\/pre>",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
-    },
-    {
-      "name": "workflow.engine.starter.manageable",
-      "type": "java.lang.Boolean",
-      "description": "是否可管理",
-      "sourceType": "cn.axzo.workflow.starter.WorkflowEngineStarterProperties"
-    }
-  ],
-  "hints": []
-}

From afe5f7e70765d60160a7845f65fe430ef44d0531 Mon Sep 17 00:00:00 2001
From: wangli <274027703@qq.com>
Date: Thu, 13 Jun 2024 10:43:34 +0800
Subject: [PATCH 111/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?=
 =?UTF-8?q?=E5=96=84=20Starter=20=E7=9A=84=20properties=20=E7=9A=84?=
 =?UTF-8?q?=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/resources/application.yaml       |   4 ----
 .../src/main/resources/application.yml        |  22 ++++++++++++++++++
 ...adcastListenerConfigurationProperties.java |  13 ++++++++++-
 .../src/main/resources/imgs/business.png      | Bin 0 -> 56548 bytes
 .../src/main/resources/imgs/process-model.png | Bin 0 -> 82722 bytes
 5 files changed, 34 insertions(+), 5 deletions(-)
 delete mode 100644 workflow-engine-server/src/main/resources/application.yaml
 create mode 100644 workflow-engine-server/src/main/resources/application.yml
 create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/imgs/business.png
 create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/imgs/process-model.png

diff --git a/workflow-engine-server/src/main/resources/application.yaml b/workflow-engine-server/src/main/resources/application.yaml
deleted file mode 100644
index 03eed9860..000000000
--- a/workflow-engine-server/src/main/resources/application.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-arthas:
-  app-name: ${spring.application.name}
-  agent-id: ${ARTHAS_AGENT_ID:${spring.profiles.active}-${spring.application.name}}
-  tunnel-server: ${ARTHAS_TUNNEL_SERVER:ws://localhost:7777/ws}
diff --git a/workflow-engine-server/src/main/resources/application.yml b/workflow-engine-server/src/main/resources/application.yml
new file mode 100644
index 000000000..10f029079
--- /dev/null
+++ b/workflow-engine-server/src/main/resources/application.yml
@@ -0,0 +1,22 @@
+arthas:
+  app-name: ${spring.application.name}
+  agent-id: ${ARTHAS_AGENT_ID:${spring.profiles.active}-${spring.application.name}}
+  tunnel-server: ${ARTHAS_TUNNEL_SERVER:ws://localhost:7777/ws}
+
+workflow:
+  engine:
+    starter:
+      invoke-mode: async # 调用 workflowCoreService 中方法的方式,可选值:sync、async
+      join-container-group: false # 本地开发机启动时,是否将 MQ 消费者加入到集群中,默认不加入,并默认生成 GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_debugging_consumer 的消费者组,该参数只对非容器环境生效
+      manageable: false # 是否可管理,默认 false, 开启后 Spring 容器中将多一个 WorkflowManageService 的 Bean,可调用受限访问接口
+      broadcast: # 关于 Starter 中监听引擎广播的事件相关配置
+        enable-filter-application-name: true
+        filter-application-names:
+          - 'workflow-engine'
+        enable-filter-definition-key: false
+        filter-process-definition-keys:
+          - ''
+        fail-handle-type: fail_back
+        num-of-retries:
+        wait-increase-factor:
+        wait-time-in-ms:
diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java
index a826c4e0e..36c17338e 100644
--- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java
+++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java
@@ -20,16 +20,27 @@ import static cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum.FAIL_OVER
 public class BroadcastListenerConfigurationProperties {
     /**
      * 是否开启根据应用名过滤 MQ 事件
+     * 

+ * 如果为 true 时,在不对 {@link BroadcastListenerConfigurationProperties#filterApplicationNames} 设任何值时,默认会将当前应用名加入进去 */ private Boolean enableFilterApplicationName = false; /** - * 仅过滤这些应用名称创建的流程 + * 仅过滤这些应用名称创建的流程实例 */ private Set filterApplicationNames = new HashSet<>(); /** * 是否开启根据业务 ID 集合过滤 MQ 事件 + * + * 业务 ID:从 OMS 平台中的“审批业务”查看, + *

+     * 
+     * 
+ * 或者从“审批模板”中“业务 ID”进行查看 + *
+     *     
+     * 
*/ private Boolean enableFilterDefinitionKey = true; diff --git a/workflow-engine-spring-boot-starter/src/main/resources/imgs/business.png b/workflow-engine-spring-boot-starter/src/main/resources/imgs/business.png new file mode 100644 index 0000000000000000000000000000000000000000..09051ab51dd5da1472c285fbfe8c93948d9fd02a GIT binary patch literal 56548 zcmb5WWmH_v(l#6@Fu1$B4l>vPALoAW zbDrPdkG)o}ny%W_yQ^yVzN%_MRldq#pb??HdGiKCPF7O&%^SGKH*etIqaeLfNF9O* zUI~Vl5)vwM5)u?DzwFH{ZA{<1p^vtWYE|e}c|Xu;QE$OiM^D;E$tsd1uhhyv$0$ON zTe4-W5X)Q64T+KL8(sabE4k9=BlhQD<0OZIp8t@d1zo$Y&rzqo+=DITYJ1yrKLhBS zkkz9#gxtkW%ETp1Sy5II`m9+;<%@Yul~cs4F#Ib;{vtgU1Vr}RU&dK0)l3s~8_FDY z4FOfOR3N*&%<-jvWic;}6Q!q)*T$si`@PE&;;=?}R&7DQB|PR4q0Db??fI=-8=Uvs z{+Q z1C+1RB{o#e{^Y}KG=6%yh_KG`s~{~wh0kpXFR&2ef#X0np#Cm_g%?HTBWj+7QM;c^ zY{u&|=Qq`oGgDG}!}vNzc>@<>`3CWI1owIoyS)_EB!2M(GARqlD!b9Qorm}UUw6(GFwDfj1sHHXW zqlH4)^rwDO|JJukm*cKy>89sql{COuU@YMRNu&MkSz0pJz71|a7EQmhW*yxh-%nX6 z^zeUt=}_Lgt12)sF<>DPE2U2Eu+Y5!p^Kw}_#RG542S*${3JWn;xeH`jb8U7m|LAV zd&=Zz^iFi!5#uZGKO%Ph#Hhi7>KQ7Q`DDsv1eR4Et6QsEUoe=LVA)4g+^$WQ`}#=57{AY<$U zn;$iEAnyH=={Iq_;obbl^pkJuqy9HD7^R8B!d%y~_ZwDW-Md-sHL`}sNe&=?5&+3S zIg#I-6zX=v^j~F7BYa~m6&~#%&?W=#I1sne(x1N=1L{-^Hf+RTkO%eX;nH-PcO&~& zPjnp)Yi7a!7&o!2xYmBU)2wO_khxqbq&3;yEKHwx4-wC?pgKAwL{~LgsKdVU>81#; z9?C4psdjSd_x|r0&!Yqy*Fl|H$)BRCrXzTj2B>dj`SXZbYU}o~b`$F?^qe$?We3v@ zLtRI#mDM``yR;1&_-ukQu2Hg&KHL>MQZH1H5E65G=_6)~@#DQj{w5dEBUF4k_Z8hf zzr3#i*_Z#@5|D2?PA(s=OH0gNxD5Xk{|sCV>}#i-(<2@OLj68oXHyZrH)_b$@>O%Z z6p8HR=O^09m%)rdvP$p&ZdaEz;)&v%exvZ(D2P9_v31PNoM@?PKe}qw`2mMjI+|Sp zNCs(bhVtL7_SiWb#Bp^xsb3BdZJ>+l={iv3D!v__{TS zCNppG_&wQg?z>gpA@Z4cd4JQWYZcb16Z|82m%hd6Q|}#TbOj+@?8}8A!iK_Pz<(|I zHx0aXVCdX?X$m{?Lp9SfMq z@O3XXOn*0Wc>xI_GCkM%tc76$%xD8AFFw zJKU`A{+^58n{ds43MYf95r{A*x?Ozh3k&0>+!6mwiQ0=H4~37B+j=$4AsR(eL&&mT zE8vp4^KO<;LT9Hzpi_P}d`&Jc?o-4->hbUn6XCXNKgF6|9F%Skg_>q_zclYPHswqC zHam1@=n2xX>NQ#1?e<1KMjsrY{S2GRLWVd)Y{q*c*3QtNY8#H z>NtQfeOg`TGurJdW1=T}>qrWH;0e+qnvwe)*Ta}~x1A{R4-&$8Y)3T6iiAY-i&VmB znc;&73Du*bzYbsEK|fjzZol_iZFN;n7IE0>Z3K8eOP=MhJ2pYl*$hy_$SaonCpFsc zHi>Y}&fY1su{-n48|~;W9O6r7rp;Cv9uWh)fvy_qE%>rjkOQ;;F0U&t{ytPStPOWK zKQ|Jkp~pau!oBl6{TJ8I-vLc|J0C2E&;q((#H_hA`%eml-a*Z|0#R;X3`Pnf>~%ed zLvQW%>#fLd6$n~aKhT2sA*~$1(B6v;@uB8=8On3vsyPzv( z*Ms=I@r%IlQjJ0s6!_N5t3jd14T(h1^Bz~({xV_vG}a#JpTk^vz5;T{oSLb^jqJHi9x`1Y~*KX65!0@HGL08u88tiho zv^4XsTgTpSGoULp4fX-@JC-{z2pd06MOGH(g75ukns^i-e_ht1{J2pVeV(VOL=sA- z_?5s5r}IGd?(IB(DeY|K_u4O9uFdybL}sE}nk61nZ)r<5ev8+|<_qKx2Z>$g(8Mje z|0Z-Y9NCK#HLl})9KJz0uo!{!^GvwFI$78}`Ch7Vy1SRI+RpWEk5yF!21Rd|Auw4n z&^Zs>q{>ZS6zqj^L+FenL?{WpvXxWDEA%6N)gG%e(t?PI|ICOny%+evgn=hQ^Xj_v zKtxXWA>c{hkn29LttVDvBzexocRtOj{M^f4DSe1Sine_tJSIq;brKhIk4TPO;}+F8 z9NAKz+QaNRh91`}k8&s=LO zB5e315Nt;cQB9tf68^0)02OFN+hQFHnrs{!DhSrD->N8GqWm|Y3op@qxL#K&|p@4W~YmWPU=`+gYR_A<_pqNW>?=#^Zzfpz3TC| zXleV_VLSL&K+nZ#+uTsdB%55Kh&-7bddUEm&V)wuEMZzW9ZP>bld5o~RTlx4^)=(< z;0@{Y*gug+r5M{{xk31@_`)b`{6So-Eo#~xOCci*yf)lL#(=_i5LA2SfLPIP!2dFX zx_$Ui`)pc4S+0Z48o2HOJ@n1_edT`=EE9F)AV5-fW*Cl-{s29$Jg7luW5)` z$W=5C;qf}&BjRPn+7nD3-E&d?j^=tH-=i4bVL^ucbycO62Mc&#vv_TnQ_#Kp`uzu< zIf6BISU^&<88gjplb=$Aa0W#mEv^cbxE~S$MOj&5IWspXelZ5tY^NRLI+$2wa_-WAFP&9J7?fx$% zi6Q}$=!;Ld`|*!AiGZoJ#o7RkM$?gx4^Q)eP|-GnU5Bt*Twy5eZncry_Gn$B+(#)x zu`~QGR8@5gnj4}4z#H8TJ}u{46ASyu$}Qo3R$OS&2NFemH=<9wQu|(|>Ky`9B;k84 z-XJKKxUxOC!Dh{dr`dQA6Ymy!!B@ubCh~M30Y65QAB6sKf)C)0Q+Ic1I&!c`mzf1I z9-N}hU=A?ysys;=tSLWTZk!$$eU`-=a4+h{_+w&3lczcK22g)jwhj`PO}pDfqbw)L z{}_fU!WD&HAfEdct4ge*M$=PAn^J1i*wasynP@-TcY952-+19 zkJSXii+dnviAH^Wg+4{p-gYTmTS9ISG8H=Pm+x10(aYpo$mxgVzt}$1m8(Ib44-*u zm}^7SeJXsEL?np~=@7DqgB1}H8*#>3ZezL*mg}rXtgo|0KLykScQ6v!QaVmI7CFqG z-A5ADMt{^F>`Z?xgpvwO^g*@{uareOz6;+k;4M;M)j3|FCns2 zHNEAL7!aK(^WF7~T4ZskuS~bvU&QT}^hd2n{k;R(iqGq3?##D6`dKBgmf2{U95ShA z)y)@w58RLs^;XkMark>aC#ZBO7y4$BSi(O=y>3VO>I|Qd1b!W;cxSIlD5Y?79KLky z5s@h?{b+O{^@7}+&m`2-uysNOo-S5huTQ3xQ-$yWE)1(KgXsgHh77k84v&|1S4*DT zYM+jgYzRlAV{+SPkx+}U!zRaqYx1bKF3tYF)%dA9?Z{8L8TRJ-fCRA(fS)cOmz zKWFK8Dv_R;NYMxS7QgfJED5CPXbB|2(pz(z!z0$!hhYV zVjf7J<5hoQ=2V-zW3k80(M+p7K)~qWn?@?sf%0-q@SOcl`RS3Z=jwZ|nbO02viV!~ zWl`^!^k77;B47G7cKy4GFpbzcH9nj)s*=kjhh>t@3qeyRYV0${$j^MFRxy5r6W=&9Oxdr zUDvC4v6pxi$$kp#P0=VE%qHsRrP{TRhA)PGX6$zK^SDSYR%>L%AQI|>%|#>G;tT+H zdFDS^9HjGwq~0Q}No94?Dsy&T+3GZ=xX#GYWqu(Qbmg@Ki9Vo^I)kf`%-w@APu9|< zK_qfOEvm(4Yt4tw+VSc-zs-zf726<>kmRwx$;|iU03M-)R@42~gZx0MLkHDgh|OPk zO!8^yXdauyf1_1@U7u|bA^&6zj=f;t&gIp|rG795iBj6c|D~GpSpeghb)h#o#1@os z@JFM$vv}T>RuY6(n3f_Wb>D#*F!%8f#LNWj94u%v0iLDFn~F8%l>wG*_e-S(_+2OW z<{7-AO;@Zf3vF@L!N2iwED%e#IyMqlruxH_2z)3Yd7NWzlm3DCBQ*n~d@BY?SIzqX zF)Wcw@)R&zpqjG4WSdr$PyZhwj~GHCT4J`gYfi)a%_z91LoU00R5K_Y7nS>+AF{>D zf@pNQ$ioFf%gY+@K-%oDefuL>xlUu`nCQMu>>dnZz!j}ANazK)DJAgI69z`y+QkQO zYqND;GNz0?y|5|Ah`FwNx4Ii`Cw%yvN`JJbeSmlG7Ft&m- z;g-}EoX^))5|+?1?NSyZ! ziQM^~b)0+m9&~pNJ|7bEaV}P~&@afaz`VqXU<7PMULlb)NdOoHkPxri=c1=I0$D8S-4}(KIG(q3nJy`zz|;K1vKtK{i6T5jNT4B|+SjLt>&@2lsYfC4zMZX~ z8DKx{@C}|H6J!~(LN6y=;H-q?(2umJRNi-f-dD=+qXriTPhpDQx1;kjCC=6Y4^7*s zcmw02_XOG)N*UbI9k3HMu44YfI5qH-*XE+RC7m)i(G@i=UZm6t@`O-A(&T=zj}nKW z0k=7nnal?P4=FceJQkahIq`;^|1W!A^2^=a7(VOu>}CmePCA7b2%TuHRm~?hD5(S;y5$C3K$N>V)wZ^oHHz zbT<(!Jm6)ymh)EmsAC6poFKMQ|Lc=)eqCpwB5m1F0L1S?q=(l;(N63u7$?N_9m>so zg?)pa)43=0q(u0!fSZ`0>U zS)I9qqWQnCB|=L$Bf=_upj%(H58qE=kfm0CtXjB@F>2O7Hx;ESMi>3$em}RX&F3x4 zbQcm%Et-va(l&l`G+9e0JZ3#gL2%>e-uW=_(`vp$IGx{yp#8e%iu;Ouj{aIOsX#ehzPY*C z>FDq!hw*!fO66L6*^QN&-zk>9qPaePv0 zKV1fcm^TMYd+Na$hS)PgIR9;s#CZ5*xe*j80Q=cn#%h9uPF$kMzkLO6 zEJ(=Q4h&-lpUp`s`@inuFYOdhgWJW4sHZaB;7to}MIL_t`t|GJz4vA$Y}b4a-ctcV zdkSH(I;hU&U1KP}teb&=poWS?9jp!}cwQ)5FVCX8g-#X$9{RcKD`fS@Y*9(MieR&$VXLocaMsenY;8Vp9p` zj+)P3A8co26G)I#h3vde=5py2is_QC!Qhf>4rTv_OD?qXj|2>~7=`JZ$I63adI!&~ zXFD$D-x|q;!H6c^F!$h4Fl?WkDu0V`@am1yM_t9=VyA*GMl1uFNPI$-N!Px`l{<3u zwA@Ku;B?^-s~VT=kB!2{OWd^sK2!>SF^C>$n`TSr*<%eXaI%!%IPaT30L;@(VNlT| z>b9O({%}3SkObIccb*BVGA)N4pZ~{PG`2~-?iij7;K~(@^q%`qW^{mijju@WU(8q> z_V0=t7hnWDMPK%Ai;+$`NTjL-k76Lu*8y+Mzq1Fi^gD=6ZU;lB3rjRa*1wm#lz!o#vI}rl8A6Z1Hj_6Y{ z-P(S_WZsRhn5ec)KBh!Xe=mdRik9DG8ldk>j}3{Ls(3kCj{>$RcM%IEkCNeG zF>;17E6Zw6jMqHE?XA?M0U^BgW~S$JGa)|pD1%L)+hV+?{73)tKFTs^ z8mDE=2lHEln5iZQZK1k!Aq9bQ;D`8L@sCW9ZRl;M=WWL1bl?>wYS z`U$X3=2q`YALeCFP4mbeYpEUF64)o$e~u)SJmnQMu~=&Y+UxQu#>0wxRB zom->y~SF;esa>ppof+`MyN;i^)_K@!3 za-lOpTIDZy?Fc?9uLfhH16v942$2Ii?9n>-oFqCaZ=Gx!DXsw;{<`jaYJZ!Ecm?#U zbO`7936|nb#)XF6Ec58nmvvO=*OHpG=mv=_%ZBV0GqzsD6Y`X?+-VAAmGe=R3fT_=oqEFMcu>&jEK6{*4_ViYkq-Hq)#~xI0jF5BC{cgE;LJfz z<4zVv4F*4suj)0fTGe#+9hbSTdW0EPOy%#UrWI&meX_Z8Yh>g0&iNz?!VkNL+<&sbd`ATZZQW~FK z5-i_Iy4)b2ejXCGUA;1+$JnBw4C|%@cGkL z>I$=#C_;4nIb?1A6?F2j=|>hJjnQ4HN4twXF}yq7+{(A*n3nHq`i8W8(?-o+tq1d0 zQb6^j1TG>SU7pt8a`06iM>dGG{Z88n?*)-r+xN^}YUiU_P30B4XG?rQ{h)83z*s#7 z!>$BL2-D+6wLjlG?h{H!By*!kdqvF!-n$+wboUvDjdKi=n!}>TE{xi*&VY*iOQHrF z6YMJWJ|cx-MfzSkeC;fBb0#Jp7=Ua`Upj&~;I;Y{v)2P!N3SIHWE4!85&rZ%)|g zaq3_|5M_nWnlx^;6`+VaQ13SR#cJ}?dz5Ja+p z5WA-$u*5rH}~%NAKY~|0@4gKok%fvSxD!Tz>?xS0}9lhKomiF zlTU2pK8^`uF9xZ|MMHicP*k~!ET_!|FmCoC<{3QFKgp}oC8(Z9H?<=JQ+TY;bX@lz zDeztY76=qlgfCGHIQ~lLD ztSVKKd?Np8I{#^M><_dMk<-~6`Q%>riJufp=lm6xg_w-DE5VDAH#}l|$vIW#zR%Y9 zxQDIuneA$i`=XuQo0w;*?fP5e>(MF{fi+O0T-Q+DyQ(8-m)&fe9o(&eBdR5vcNvh` z1%8(>@Om2M?63BObIxz`tU3!$WG?d;cRrfoIbPEQIJ}M6s5dB!2mBoSjOgtA;&)c! zs>a@zsbk+3+ESIrYq^C8&xO?6H_}N~$}&0M>(25X$tUZ~ocx=R1^BXJejY3$uZ&4zN)6fGB9*!LL_V#OdHVHl+Hr=bTn}g`BQIMWR=} zjj8nX7(yf(KHcSM&=(3s{gr?^k2D2z6y^9#EPRQdd-;6P?mDVKHef%3?yuAufh=>;PkpRix{Ug9M!_6kM+_zT8DGz-jUEo!QM|F#GB1GTOq zcNNdv*9k;11Yh&{4%7Fh91MPa;iw2j&dUvEF_&n!J|gSJ%;TQm1~P*(BbZs`@)6!rvK(($e z`!>laigb}LdAYIY;3MF`6|1!2m%*96@pxI4X|x< z!M%_R^4cwYkz!KCn+xktkU09u6j0}DF30(pNwXmKCNpyZ1@i|{(MU*jP!sd$0=Wdk z(cZ8d#l4=x4UgF<$vg7En{)KY%844v7B!dIe@{Z*F*B^s+-uKjpI293NRHOS)vSw^T$87f&89bCP zpY2X+vCP98UshnLUS5p3oi!N@R=nKSpa4Wf9%yesi0W)CD|V;1rpi}YKq{ruBE0_WK8ZVg zBGmVu#bz<>(mWi~4Jisamadu=YfhRQVr0T#WgdqyHz<1~Mb5$DXEr#-{E6XMiYy$t zlV|^-7T-Cf1i{LRIW*1*yvaTo>RPmZzbuoP6&fX%r9%$!7JD%n>S9smcCZ@{kHebR zsB%q;1K~GHOM5V#Dfn$OUWc5r!VH{T5(8)}=;KU4iqTPuA3qIQU;4TSY+_li_Q*ag z0NIe-*av!v+P|&Ve(XY*21!FUwg>I$`pOq;;!|cI(rt-X=WLI|gY>7ii%-A&GlVOc zVJ@_6r_KFxKj`@uK;QM>s2KLJ9SO@;-5EC6P0!W;SRC6+(ejs-HUEl=G20Y@5AGi` zke|?<_~bUQLLiKWXbeC3)vd?yc&<4nu6jPe!F}l9TjLd(+oTLhlbZexiL&-hF83`B zF4#0Aa@nmajZ%Tg?$C`65$M{qi-nJmw*AxAeG&BYiP_X+Mrf{Fn66ePKRSw=%<|dD z**_G0+9!2>r&83qZHP*7{oXIl=tCU0KR~r(jBDHc<FP z56roy;K`GozAC4<(c`ni3w>9^=OT;}^&;H(HkmByg@nBDTVX6c<4@Nd*C@Db-#I|b zz>h5JQr-$Z_4qCi*)1|8y1ErdKp#)EQpkR-=-H6$E%Rn?5F>e^wCPns0q@OirP|;V zh0%ieMhxfHe3cc9z(u^2)g1BSU7*@_q9cC2yHwT`MVA$9PDrbe2+$J+-UtaBsTc@Z zZ|Ulji1vcVW&{}Ji?{IMkDFMK{%4YmDT;kWcZ|aKac4Hn+NC@Hca*?3}s@fMF^9_KZWIm;r#2hD8haQvmI2T2<^5h00;F zuw6|0W-9wu;9;*n7Nbw^6V7;_YG=%U3yz}bQRr)L*BRJ7qoQY?y!-AV$ zRehzU|CEcpPVJ+FA3h=F>yJ333JYzNyXHjw`F=j@zcR30QQZEX*v8neU~oNP-UmH) z`By~yX>0&s)@%}>@ikPtbmyI62 z`ioeyS6S4o$N$P-_{Co-X)7qF!T&!6b@h5dCta(D{rlCQrqAgePpIX!n+McYCW=IM zZ;z#xl|KhV>xLsbrs(BohGh$bd8}1VO9<6zW^c9Ug&)x@@G^rse;xBKwJ6^8wo1}SKbkL+c28}b%E3rILEiQ7`<(wXwY=t7h01PSZuU;+ za&~IE*g-?-N3|&vi&p25r{8!o8%{3|?~B~^P=xIRUn?MTm* zYLE1rn#jEI?#sAFlT3~+YOA(l-xRN=*nv#^go$lmDYHR=2#d=J0A1?usU>I)o3)_cN-ux}rD^ht{im|2TT=J#htOG+nuvJ1tzuRJMNs zv|SYpAqU?aUd;C}(zJ^1dG;Umz?5gDEb^zO7FR<_>6rhcd zBwQ!|uA?$_sQh%QPYW5^t_3F>BGwVmYN=w`k-u&S}DCtp3 zjx}vqHc31yykF}56RU*pC@hL51~$bvZ1Xseny=qmIb^-9k{)ol&t(j#wM8yB9cq`C z=R9TU>ibPUdd_Ad{VjmzSRna(guK@%lr&#oVvwlaGLz;3c3hFy)Ak{*Zv^R(E?toU z8OtDDj`ITyB6#}rq$%GC;hiRj`N@lZw7%0oFx_FGr_cGo<)Zc@o_jd;ycc+y;wfL6 zED?fv()FeKai!M%_=ekTM>%e7b16#rbS4*B*nR%Aj!QJNO1WuSK@3tqjDN! z4*}&VD6KUL@O=o@#>Sw`pKG`LbV}sR6aB%LgX~yFajy*7j^```C)d*Xyw}pSHQT~Kg z+WjBs)b?V>RhD@8RDOZh;#SJ(^7XugO)qz7i={?<_lV}`y&mB{B&boCN-&=OEtY6i zB~B{!ep~||2);GFJ}|3aT8tY<3fnAlFP#ex9Zwe-HA&}nfWIMPk1|twS}t0_{%kx< zjfea)6@-2O4P(nQ#yXL7)%CzB*N+ad2-Ekubcl613>}=5)L2Cw&ESp4Mh^WL&SF1= z8+(0*{*ns<_{1kvp*CA-}b9hg|v)HjQN zfz&F$W9>RUzFp_>R%90AOLL_4y0{E;dj2Lekt~5UX>O0vI2>wDOdPl+()HHs{%je^ zUas>zg~@WID4LewgiLPDU_3A{aUdQ@U6FWeHT`gdgkX{ByDc?HD&=Ud$Tu#U(V99Y zxV#bD>DAheQ(}{i|8j-h{xXG*%N);SjMpeMK#$OM{$c!GMua9AFc1wr3+HySfhF~@ zVuX#Ob4Z6xU|rE9+W*c6Lm#(>EL{=?`y%AKb;+Q;}g9@JWb*DcNqYFhvK$_WWp*YV^&DL&MoUN7=AtX_Kii%y zyslb*)u^_ot(V+=%c##ZPLysE?@UXr)zqC~GJHB4_uy=ASYcQ0hKqMXEBTq1K%dO> z4(ECtAOgf@kLZmQoh)k~PvTsh;k5*x&(yn;FSR=sx=->9jpi4wz5K2@n#l)Nw5?d- z{P3G~cc(oyXvpru@?JffrG4u50Vo6nlSz@o9*}vg-QToBX0~a`z=)dLdn^Ynk7Vo) zpw1^U=d;BT#W!bdCq@F#;969NTK6xP18O2lU4rAHgYxMn4;Q!9PDgL?C#lMM)&>;> z^rJSID-zw1j{!a%$Vmo%?2u5GmDam8F)sL&q1(%99s7cp))O?3%T+83X0F|~{xCxF zbxG9Q1LTZ%E3m)D(!eWN!0q${PsgJPnarQBI`lm1$1PY?VRj8&&8D&y%uZP;?+H!HadJgL(`_VuOa`cz6h z6H06e_-MA+awLJ3pusPm^HftQ&+6Pt8tvMQ&Ihcn3)J{y}x{ApghJb^%uKDl17*8>oC zXXJkI&H&y&k&|2W3B(^m7Zhu`nYK7nWyw{t-sJGNLq4cG162;>dh724u&3pfQ2yK> zPCQPW0f7r4x1?=6c*!127wdev4j@EJXfLVCnvNy}^lW=XxwA>ZwgyYcDZYQpI zGI7Dq%PD*KZ^IQ>bLU6}lW%>mRt-$AfuGzn`A6cMn-r71>H-v?Vkwvw(`@1e7fbBw zSDW;oKZmM5sWvFzlUGOv9&$46Bm()DP9uErE0Svz0HeVU5k`Y2tu=`7hhET`V#MP1 z*M#a!dU?y>i@={O??DracB}6{HZ|MHm&>_Gr|YTGr^e};%f@u{Eo$)@l(su= zm?K(U9T!pV^nM{FUC%B3<};Sb!^Q0F^DNYJ4QIRQpF#vhjM^A)g|62DZ&`E60tJXv zr9a`#adKqK?b+t#lk(A8e2yT}`8hK>R1Mo2YUrQcZv(oV#!!z4SJ?x4YA^}B$Da`n zv$`cL7?sg3(yoO~s)q1OD*s|1C07ysal}f{5wo=XUgR;FqG8`XVd#em&)a3$+fvW% zeJv|+6gLefs*nFXCLA4()4511goAH2mGhP*g)78W@}Avdv7nqfnTB!UPK+N#dUK7g zdpO?I^RR!G-Xjdbu?n;nk-&2zIb_rHwuHBeZT9{SgV9KWi879bMO<}!hu0tw*|w1PS7@I&n!|ORY4Ba}FA4HJdeOL~; z!B!OVyo~Wca@7;o+ybOG7>%pn=OugZWU{k!Xb!kR;Q{QUuhn?j<5HeNnAfxIfeNHO zuQ6+X5!|3n=CxZ(%P^P~X>j#=frL1%&uUK48Pln(dh`>f)~>msBh&&qo`(s^y?xdJv+XVsuf>ino?+YRU?g(KvSLnkKs4nH z*S8pverrNScqCG1ZlybC?x$e|l3S5m&o-C(z9*~h*h%M7P3_&yke|Nh@9I)~&c93` z8Qy+%c|yYd4#v0or1}YV4Vk+5V(;UuwITl3LB(O%$s&B_4pqV_hTs zaG%6Qz^lK*-qYhDeBcWuwHR!$9niAo6UA2>c(#1k*>$py9sXGt*7A`nZ&*MHLRK+Wvcl9;&l*+Qwih3ivLNw>C&TtypSQzy7C#OrBxuxhlQLgwLcTQ}wjr$- zY8(F;51C_LYg$~=K&D+Ub73hNv`T$%CT{>!IoY^dnZj)tHzd}(jpS1+mztl<8D%<{ z$vi6zTgJ-oO@VT<-Bp(sOd`k5O`qj(6&v?D3FPF07AyaB5w+Jng*o3_=`;mNui3jh zLWxTrDn;EufHUDTYOP&~8%zdr#N2XZfcL1)ED+iO4FB-*-A0a8k*L;F_Ls_)M3C!t zF9>^XU0h4F1F}*ZPR`~h=q3{sTZJTa@i%wj;aRff{2t%33rFH`Sn%BJ@DiSi#&>b$ z=DN0kU`~nr?v@9!)V$7lboKS~{=~*S-hsH|9_FaH?)x@D(cogCNZSz)xwm2}oY=YJ z;$D+Gg-%yz5%*zjUq34>QkaqY;{>=Fr%u4yZSXBOLsmxs@)flm+HA=w5FzM@=`zHF zHcCIbXuL}T{4S?x#|gWc;tgb{WS-^iXTos&2d^AxAs zM4qOfi$5+HAsmeyC)#nZ^;ZpLRMweq@9T2<3d{-n9*91gPe3069>UNLk6qWZiOgS! zxD_mMDar$e{-BNP<3mphuYO_9Wu68O(W?Wa2qbVC=JTtn)7dE$$tE+r+SP}9Rj_X4 z^h4Q-TMtLYxlht+@9~KjZmVwk-<-!p5?hywdOw76WCiB)Gw)Y_KMOgm4L_AysE(tM zDC)>*F&LLbO{w|QH{JfF(16L0#q1n*S<3UdMnLC_a$5vWukYwP?-BMAXDXOR@6$l~ z?w5AuGRB@TM|!64*VcuLnG{xv^Y5>1-wcJziQ%K z8KbH@U$h*Q8Oxc#Jw;OG)4OGa-3V8?!HDt*rUVuqqJ***=ZJ6Hqo8L#vv9JD;3KA~ z0AV~?CWij$_MVSzFTy{`)4d@y85|xPxXQ+HkMHf~6{tHMiWOF3;-YJ+odV=;e!I%w ze3}f?`7}fpfOp6); ztmign!n@SQ^S5~?Pnpis9X1w0yXI+_$@!cHwL^aVNo%GvYq?!}^j_UYxmgVrrDE>_ zPIUTmMog=|LaTNBiDU!2lKR5VwR7iW1_Rq<0uK`&nf=0Bo8@71f{ROENBHkJb_PPL zOa>8G$W`xmY5J!L+DSCajxXhF*znERHsWsS>}v0(8=UX?b;}mfCEikv?bcp6uy)`} zyK`#rHF^k~5ALCc-1n9Hkc%eZ8H9)MJp6%%E_Z}vesw%=4ds0;+(rr+__zO#AN%6Z zqD+N?vr|_XMTcf5WUlmY>g>e<5Yg<+tZZ0Nqsb)ROk!t{il@qMi8neo0hOW0{9aX0sdm&qta6qP}8_pR&LmHjs+C^6#TM zazHnC6Tr=aeS2vg#c|g^NGpoJFXtmgmqlG8ipfrS&T2`|?ML-;rGNTcP;gYt$SGA) z%AHWeYSw4j?;K+DOZ61~ZJQ1J4`NI2#68M|$f;3gWCnORCw7~o{I@qoKJZnpyi@In zW044t_mQffq1WI-l4rmUEP|Kzi{Rco63&*~&$rK)oMG7U( zeYUDc{Vj$YNv_}O=feB9x+6K=w|9c|pPNTjp|}m4+(OVv$=}n{Z#j-TTryvIo5D~Z zb={UA;9Vw$(98%H7>~Fo@sI!H30~WsvutoK!WRpo)_R?T z{en_-NBVM04*@p0eg4K}-ZgcDsM^K_I&g|+N+Gc z0`YA7#3~Fa$hDe79jYrD&PAB(krs8{`LyaET>Qh^*Qfbm_v^qh|3}uF8^zf>h(|~r;8i^pRBRP90IJ=u zW=tGLPn9Q|%u=6!(e+`HS0+Z)5@LLNBotq+tR$S?JSaoI~zX+P`oH zdVxKT?ADRLo(e>;^1Tnqif@>xxnSnDk$lt+GRU*4&o(aMu=8$8;Tjk4rQPEuhfLTb z$$-u5`KuY@{U?W3GPkTD=!11-d+j5H9yav@+x3c}A#QKMN zwBY3;J4iI@n$p;1xcb|NS@6H6a%W(nYCVwMwc9hegM&5i4w2b|WZyq&_Q*n`_M}wz z;RyUw$lj6csL!{`y{N7+F_42*b^`sN8KKuz}pkkv%`x2|= zh;21xz_xEAF_l+gzIuvZP#rCh&ijqLW`#TCxxQ&5rrDD)|J!4@bW8? zJu-Og|0C+H#v=P%BfWhz}d_V!3Vs2gWzdP-Z=j?&vd<~#q4YyUI)_0JW&Y$^e);qG*}fd!8k}_x z62&T>E~#%}@FQCh4fx&MGu_{Elo4k7woR!w)QP6KAPC0NFpLx)yFQ*_ZxaNR zY;R?9F+(KO#8{IAVeQ&)srVl+XV?rnUwIxk?UEf#UhdEApN}wcPOPy`@EK(;BM^JV zpz!RGG+)i@$P-2j+|fkhv4`6>ZNJB3F_sd$Lc!lzwh0tC`ZGbP?>I!MT5qZ5dD6Cl z$8FZ9$ae)8}Keg=&>bde@aF;CAs0Ce) zT#?D0m$-e))I3gRM>k}_hGeNZvbf1-K+iss^ZK~u zq;RfG1LtslIDt>v2#?h?!my%`#a_(TmT}c}*+v}$_biH#*L-(8gUa@BzP!$PUzuma z@AXfT6N~JL$LBa?cVoN-G7Fq@78^vZE*R!WfK`l<-}HK*x3^* zTF+$~C?Zwh=-^--dLZNpRYv|ixb6702s4=9ui}2uZ}S^w8}guAfBp2v>Xh$2^R-kR zG7C3oMt9HH>j-7Gu6kmw!y%+o-}h16!^4C0p50+nY{8is>R#0M9Y;s|%_a5{f^L^o ziZ`<{TRRyE8s{j{{o07-OX?3dThXQ&;M0w+_}ExO7q^|!6qt8d(>$}+ zhYOXQ9?aZa7o)5tHp{=%Qw%ac>ikM>o|&1Ee?QA^*bRrrW{##-qD-k-?dNWeSoPP1 zBuhxET$`Q#2xvYZeA2dnv{0flpbaZTK}A0y_}uD%F7W&S07JB}*zf%t4WUAsKexA# zZDND!iIM~K^hwAPm9 zreAo&a-p9eO)Qw%{&Z)>vl&Xh7b{7W^Y^cDGr&1xez`Z*ukZ>A8;j;+rlIf6Zm4`d ztD=}fHmM29JNaFmXJNP1A9*=UUpd+F{AfqVz>vRiLqflQLFl$3T$Jf)Nik+YBu-)o zEJf23u}{CXn_2axdtzsqbmk}F^%y|k=fG92M-h6%a7N8t2Q(IZb)c^+AwKXr0``{p zB#+DYU#6kuj#a&tI%yOAl@{V9)a_`moPr1knszhs>x_yrT(zs~cu!h?C~$9MVd~cc z)o&LQg7W-0)zC7xleOTIC<5*{i3nW7WVb8V6C4$I&0}}!6Hw*Ba7gL1(dplRzv{M*o^NAL*o{twKynX9 z(C_tlcg1>m(E!v_Y2o=9pHMLSnm00&2LH-cDN=y5k<6C`jo-2T1og7QI*dTx)P0^m zk1L|6us(Wgf(xR;y=A5k8sb~i2v+^v~?eCWPN&+b3z)NfUh0l|rpC5?YY zCb;Z=%Y-|}{}9a&#cg|jx<7@dEFR3!TB@`7G4%S1XZS3sB_fq5Rzug}TWn)S!fdJ9 z2=jim(E!H$Q*{tp_}dN0+g1D%k)5-^HYQffa0YB(_#a_i5eyvtWkJix zt65%`l7PRVUnGxXf zCG#I34nV5qUUfHjpi$8pJjMLYN$A87X|P?5`1>>^NsOLI!u+8VqdyoK|6R}XZkBJv z`&Y|%Rds%0(SY%oLX+Y$B@Vk=_4x6*Fu&h7rtsThu=eYQ2CX<2==rHpu7B7!Z{9E6 z%y-zMd(}zWAI~xx*eiN+n;YC5*IGTG2A`fIKCtdVY9~-a?G|e&=gM_zqKU&KVBQI0 z39CI1QD-GHXeQwVAQ5#exE#)-LlA?qYqEIVDi8yP^43Wpc%3fiL)0pO%^0l-SS6V< zo)!!jdLu;gCz*f#G$#Ouov+&#{MW(Gz%RthQCm;?L;H%E)KUyrXQ*gw@v7){7zOgt zpoQCDbd`pSd1n&rfUS(dj%W4iM=_wMA?g8oUw zi+LhNlj1YYnpyM0lEiJ#*x$m{)e6Lck8Z&l1~J98fWq`t4`S*vmgn#>dI}^=7~6Mt}fg$KeRktTw9q^O2s*I4@C5O; zIILrPo}S>5@igbYz9pL7V{T332S1-Js>63kDopoOykfxqjTr1*gdk3<)e%a5TpMZ#+|65BkDJp!eV%ls=U)+jfgmLawb6;d0w(O46?`}q zwOpvkP$QUT|9MthTU*Xmgs}X^(AsRhgUO?6TLHR4jv|Zx`#UPnapTsWKLQc6&+Th+ zF-TW*@16c|aT$mL4;FC<0>h$ueZ%*0eoHuJuj_Q1jZf;LYxcfS2+LP23OQaNlaQQ@z8JO#0GP&E}A_Y2eHIO?2^>KESA zldZ$jlw=53Be9F1hl;{sBrd*9EcgSN~g zG+*xfhwfh)sXG>r+9_rrgGd6avzXkYd&sxNp6M_1kk}|Ahoi&G8?Lc*Zoa9fD~&Qm zu5RFHxt-b2Ya0dU=Zd)ZQxB?Oa`aNDFiA24+gr{x_dGQOJ}6?3n#LFG7}u^hIB-Ge zof=m_af(^QMO8hDHX`>u@sAYhEU)PZ%oe0cI|lBJ2d~Al^<44qUtKJN$UZBfNx7Tq zCvtY%$geF5G{_7x#W93qirzn3$mc`3HeK z1y`zBN6#9jSK}cVg^+G>l%th(oT~?d8^ikKpvrh>NL~C?t)?iAUR?YVFK`}ss4s)X ztEQua(k;OaEUsJp(n;*zh&}Zu6OwJ+p*b=QW%uZ)WB&Mt7M(tm(HB2`W)IUDHr(~= zV2~)gmX9#fubQtY%?V~3=+!Zi_wd=iQ}qhMe)b6T=r&-)^7r53Ju|2wy4? z#+Voy`V{haaH%C-oN0oF3Z6?G6)ucG{h@$#*8kVpm?s2JNS}Gg{`g{`nZG}H;!LD@ zpu}VFa8x6;-CRqYWDPA;$COD2@+w(#1)NipbmZy$Qug6h($g1gAn@dzlW}a^q8RhW$JgJ zw>bp;0Vhk#%kj<*1$u}{gL8_@i6D-T{}Skg7|;!VSRlCy`|h?XKRDRGW_*g@_KLcQ zC;7JAu;8K1t)ag3c&&F`Br?nSAe#Gqaq{5)`i4Mdy^8_+t1b`dUno2b1M|z@Vr=Yv zqweqX0Qbi6vd}HqipB&;Qy$Fn;omBPUa+v9?bt=GAa)_jZB*NFbtQ9yDnc#*z=TB$ z>9T_T7rxhfmdLK+l9M1DuodHM1=o507i9ZOp@VEJ@hv{4Dx#yoof6*jXo+d%pz_5+ z{*N%Omk7WWss|b!>t7A&sof+TW*(XYAOXqo3zBr*K;zFdi12gLQUF#h#T#~&?Whz8 zELGtFphP3MMOWQOw=UvHaPd`L$#FFk{a`)ezt57rNs0k25D@Hs0=Pgb>~9Fq|QmevpO!A2*G| zHvkuFY$ilpNul&;ALmq&eSmBKzT^V52_Q^B7qdBkjfT`4r&LPw(>09dEWrPRY(OEv z&+I`Kp2ncTBAct?mBG_#-GA6a{7b^-2pR-wHD2cbmqRuBsde=1!PPP*KH`yg3EH4u zRm3TCdAV{V(v=nscA~cCKUl2t1r*a5le=iP)7FP2jj8#HjcsD07V$cZb3gDmyeOIUUPjK(8m8i_CNp-L$uVUdgcGO zpq(EoF7F)e{fZgy-%}C=K$yhToMf>rv8|&65Vab`zb(by8URCDcmyDoa4)wJbL*ie z#pU;<#`+SWR;>TzBK9J&z0>IxMo=hTN0qcul4_*#e<_(Xb}v)sny~oQ(c4-kWvd4y zdrlY73u1;2h%L)o98Pio>jSK`2YpyvTro2>Zw+iJy(wt+rxLrVi&Y=+VoW2b*!X3h zF?wd!nG#ZNpZw*AT8CwoIt?^7(k>zXn;`^%I^AC7cI}~6L4O}E9Ou4PaQY7b3iD=;P7zpe~8;)|av6W1>AL$_Vu)*1e5vKxSN z1sKFqNwHuP@${pIk>C6%{Et?t;-yKA8_W&|*_wsdE*Q_I2QN5eb~hQ?_09|?wOno( zCUw)A-&z}3=|rGScZRLT8cj;?S2tU}!e!nR>i`{lS8%L=TlU?fBY<1k0-56o6`F=xDSDoI`Mo z62)}@aEr9c0vImtLLL2RQB=I%Qb|cY@fz7Y@}GuiU^7Y3+^nF_;Nv%`Y=$+4mmZ^+ zY0N695>h=uuW<6c;`_u%m7BfKi`d-0E3zc8_*SGSMk_ok1dy&G6#2-ra_oE?#bh|E zZ|ayT^AZ=`T41EOWYQbFdliMZ+c)xY%I6<6wh=C*`w1+y|9LTs3j*iVwN4Z8xIE}P zH>Z&t21A7uJBfecL#^vFT{Z=6YcW@QGIfg7Y4K~4F4a-Dg*4MC1<2LZ=FKo z8L>u%6sKdaDNJu@=u3U2ot%92KK-!Gyg^4Mc1NEZDHe{IB+fb$6`F@;t(tZxzhmGz zI`gYDe|_j`!-|OnZbEKx`;3%D-Qm8>17=fG9AWlG3cW}cCiyn9Su{;qa~E&I?QclSGdz1fZW3+wTh=D?)aLSUrp zDSwx=ncWaQn{9st%6td+IV}}WP?~4MF(;~GC#E7Z zf~Q6K6$kp{o^MyQa1d;O7C;66CKJ_k^^FgJiZ*+@E=$lIs|Lg~) zD2Xj#273I3_1G{21+KJHOYPDg5N*Dy-94^`OpzilVO!aLEL-cE#8)ksCbT@sa=*Oa z5%#>@xG1)jU{@*Bx@uNm%;1wwuJ?Fz^>inY>i)p5?j_CdYojUiyuJO+iiZgOv$&-) z%hecnXD^{{2YVYcSoN0qzQCgp^_x6&3v*Hl`F~mTy>DP0OtNu4k}>byZ(da9ew0vr zxFByEd{=|YI*QjS;p4ug;EXGK1GQS}H(|5fmcv}A308bWv2tg=SixJYvoEtNC$xGJ zxdpqaq-i6Y6Y1PUYjf-5%0i;P&Iww>PYxJ3OD}iDHyDx2ukZ2Z31|vTY+WDa{Z+G) zuNRk}6Pj@Hsu%gUG4P3z7*c|{wV0ObAG6L)Ctv&e_VwFbeZZY_vBHUiSJC#=ww-8ehQc7UghAr z7*h?YK1$iS?-%xvPA^~HezSsS(KTnD*oD)hI*SRE;nFziqy~HuQD4vW_tgb$=5MB( z^jd=SD7h1=sO+L;pB|C&GVrmjcgU#TE0D)!SO=ShBvX?5^le7kKtn{Q_J zWR3FEBbpjETU)JE*{6$$m0PIsi@NBqAi;0V^A-|S!&z+}l=ur7(G=g+YZCb8C#y42 zsGji^(Kd+ITk$hem%m4uit>q32MVrDvfiX+9EB~{!M3Ly2-j86%V}fCH~I> zM*3{4q)@woKY5z-uekn-jENDL#o0P-Li+LjA)_(To>7K?t~L2DQH4BerM$Jh3=CPn zK89~h<|Vs`&@*DfxgM>F9&*|i5Z<;F7grU_EzL?``A?I?#HWkRv9Qv#D98^>Rbr^A zVPAPf+nG)*pHu;zj_z@^_hRgxDm^A|nkn}{CVtoPhE;P?M7_(b5MF?StLZpjKa;)m zdI27?&JyxKuKr;3YwT(mTHXY3FlbBfm7;{4)rcUJ(cGO+r%!opD9Fof_PBFgCKZnu5aLQQ8ak{CK+K}j2Q(LU`*c?B~q(lisHs~~erS}tU zct>lOTcs6x-*u1)o;Zv_&V>A{1G~0xS2RC)df2xt*a&9`ToV=s)}MxeGs&duVp9%t z1o>nTw(D{m5WajRG<6chzi;cXPdB{$+_Zc5@wz;K^3vdlP!?Wf!Hr1f`tgdAaOD2r z8$5^gfaTL*9lUZsy_;aIhOAd5bL4<0$yDIfLWP>EcAk5$@O``{$UvEHf+6z{6*4(1 zS;gQ47&!mo`)Y6#8R9`NoSC|u2G0#$5Y2er>HKct)+JyWGjxAg3vCGdXipxzCf4?N zf4Mys;-K5mJXUP$>2fe|cojPxhF%ISXqR0g5^3E0#_*b-|1-6ot+d=7%p5<3Cm;%R z^kTI@6JYTsh^in%w? zL9Z?db!S7?L#A3>NWd>p9SQ#ig&^GKyLQX}b_@$N060cKYW(3rtt+*v<3_E$`E*hxb@seB5&;hi^L+)7Qri&Ol0kB!q-uP{OH|3zH)oe*!% zzq4^lQ6S!+Z26=2PJ;praHshf&j0rS@)BEtBj|PC4#_@RLFpDX8o_0+0aw>QJnY3i z_Ru%tD9t}wrnMM(ui|U?<1qxK@27D2e*u7a_Uwz}$R3nX7VuYmR%SwWUqcrl9td#g>Jew@647+{G=S^?E9WV<@Q=h}gvbntUgE+3($SPFiu} z=h1oLjN6DlV$DZGTK9inNmwbs!FBHKj_Qk~aoFXJ6KYRoVHQrUdEd(|Ttfga@`1FC z{g6{zbbqFeT&+CSu$x|^vVcwvR$m2pzo4UVVh2@(awco5Xu317MJ1t*t*mvm*8js} zO{>~$3z)hzLv1D#YdRV=_a~59uvBj=e4jkjvtFp?H2gCaqi*Hb(Jh-@m$Hnsbk08O zF3yNXhaO>RR_*iNpD~?ZDbd<h8Bgshb8c)btn&rNh3Nx!e3};9_a<|thPW0AZOyawMpk#; z5Pde&mG#*MNi*O}rD`GWD927DkNqB0kNiJS2!B(XMmTL1mM4noQ+`aK=Flm4n+PQ( z&y#soo5kYttIOonFO!O?+g7#G*5+WXJ|hLUvA{~#i*)1a;&^T^ei8i5n6hL5aHTWD z^rep*IeV=8M_Z|U0*6&Hx4yts16W$`SPx`&FKL;KZ#j&OBBygmRND zD$p6ZUNCSTet zn=E;RnQb(TQj=sx&G#}#L-J6DOK0Bq?-jJ2c0O3(_3tP`x9-GdTN~M3r4Rkzup|X+ zbb1Fc>1kpApe0Xm5XFoNyI3w5m$Z|9)TsszvAiwsj+Wm>)-f6W>=H#r3T{bS80mUI zKc3EE7q0gavc)V_;{U<^`hHHR1NYi*-(v}=RSI>3Zhmf~=1ETPR#PB_&EO7*AY zO92f)G%B>sR3Xa3ul2@D$4!(Nv#3dZ6_RCUOvhP=l7AZ1{3&#aId|o3lff?4X-NzV z5JRO!*A7F*ZK=t$l|e^#wE0Q{0L@f#w;6R z9SzF%PSd3yJ5Cun+*2#fPoadtg}9tdk7runl19qkn`N3P8c=fa;YuF9PEFA?r<|Oq zw`LA?HTHnzKp5hSBE03b7`^H6=%b%w5N7)u28^&_fPzH1v}crflt}jVFoayZ-0QsW z+=J;Tl+1TiW;rgg5)DMbq;JumGuke)GML!Tpf7 zgP3{D0T6@UuMVd%=P@5a+yi<<*pUm^>orkJoPg98r9e+AE~9x^)0h-f8)Edq0WUTN zf9VSCw(*}}a@JqH?3OV-bkB39xv^b3%jrQ^jz5Q5(4mS(s|3quL6Z}29$NfTSEVOq zxb{Q4yz`X*{pFPc@<>f?pc3k7mIbiCup-u^sefS@7a|D?f~KRdIPoILEv}9 zSB!EpRC2ci>G*y)k6?TOJ0(FFtGC1%(w44_|gJ1tZ8CJo5Y;g36^><9T8A z_)qkZ#ZuZdq|^gE-7d`U6c73bkijYj2H2Of#O$-<&zzo6{|4-Di4^~hB{p(qUI!AEbVISC8 z+v)U#Z28%f5rGT|1OkmL%HAx}+p*j|lQ6woJuq3|P!fh%za zWnq(<4FU{{L=mojAz19?Ji>P4N$JA1dabpI2>+95u%~-kEGa*KCCiG9;=u2;i58r0 zY0unYNnIO)Uo$^*xY;X(70ymR3VqAyn?E*a=ORV5f>!wq-0?sgj4IourfqcUnU`L3 zZt+^^>t5!NE|7Zkk$j#eclqSd`AYz@-Jrrduh5x|DvR)20B6682g);>l?-yfZ3TaO zr5+pb<#*u8|FHhdrtw{_g7ENHvW(K~+UQxXBI2lPGR`Av*e>}F{1x^(CoBZSk+eq! zJEQvJ^Sl1R&IRQvBlNH)VM1&Z_G}&_mhbqqtjBEr3`*_3p;zwha?#TSBQIGJn7)9LTW0!ARgdl%q` zyGz>Sk)5LygMnB6FX$sfqXt~Y=pXp#*Q=+#uLdq>d~38;uC;jo<#76u83658qKb%t zD8h_UWxbw2VgHwmx(Ohg0uIM&w@_8oSz7&v`WMvuGn@?Yv3q4djgs(TN&8u@O665o z!k>T#uKMofU?AcicUkFl$h0n?Va?xpIRh2p@gG@%5G*Osn!l}jlMD7hXuuy<>=I*r z+lCxIJOvqrn(<(!XlT8>cs3hoBl#;|Ppq=I&sxHwDldx z&JDqTaYtwEcQY>K(!q%qmV2qJfZ=q-hzmde(lh$GA2DBwsImk*QaEfDD=>TtnlHlm zHKi`yP0t{kAEM&v&Mzv6yTdMNi+gY567K~4UcUo6UP=u^9A>db5zpBm%nx(_5;$6SVe?DVni@W>d>_3<>0Yr8%`@b znrp$GQO>PW^$NezgvW%A4?sYsYe%(=TGQdRNyc+JuSi&j{DO?Q;)MHrd99txuchSAESPgNYk$lkvw?hKsh7d zKflkm?oz~&5Fp65Syam7k(q7Dr{r%cjp^Wm{Ln(JVHwLH$l`WtI}v$ar?#@VZQdO4 z5o_&JxFEzOyINB+oy4C~Kd6v@*{%m0OaCyOo*hc&y-<8;u%RE%;Kj+WS#JV!Vo*tC zCp=cN`VIsQ{Rr?{u~qx!F3j)|eED0+TVFGtAD=={E;Ur&H`CwCqp{BcYjCEhbMEj7 z6+`iX<`rW!8Z00nt}MS1S}>ghbfu)RWVReBU1k-n|Ki6-D|PF|X8Cp2Dt)Fc$EpDo zn`J{t&{?rkd9y;pZO1cn@%pRYC_;P)zo6$O$Z2PS^`cn6h*3FT$}m&s^%x#!7moLx zR-XMoxwH+uM}gcPmX`9EaJ93SI9u&9TF>FbqoNp3SI%KAn2=u>0$i zJe7uuo2`ZQ7}`ATB7vH|y}7d8L4x}j!}V5=x7V}0!zn#yF#}B(Yo!h;SS2b&NZhQ_ zq%R`1$AC#vfvT>kZW1KzaHwPyhva-3$sY!;1po)x7jRJD+y-0 zM`hlM=*+G}*m`u+&gmIAvcH&@cRrpXyfA$XgBu=3EBTsX#ANz_rc@*qOOW=gp4umX-yPO#xnWAm#Uln?roo_>G5^+`W_l4o2cQ@L115VO9|XmJzoJIAiF8F1~5#K+-px#|o=K(#-Few=eJj$kQ} z*}5n0|MRGRLTWM`f5*CeEy!&8z-7~aGT-#p^x^JpI5utgMDz7z^d4`O;K6KZWOKch zk!<6>1Dk$%^~eC72H5!LktC*szOTRVl+A-55ukZz zhi8uhS>91pkqVaL>x%rfap%P5YxyN9(JHSwoFILqEEK;kcg^SXVG`vwFv3uaXmPCun-q7CZVsb*a9n%kJ_38Kh2W+p84~ zmC4w;7V^7pXD>&O$|4cKo3rzaI^x|(O6kaPuio5fa9uX7F-CkJh6{G%EJ2E+HMRM?4&K(cUsAnOWjeizllMitNTU zfm=7i(lh;$!t^j%8T4iq*>T?l*OqE0Hr8Ju`I=@rnK7{A=PC6xYc_diR5))1U(Lcr zPF7AGap&h3zHFOsV3L%es+U-FHygdDgAE#&^WYSX&$kpZ$)FD`#+~cmaV#dF6@noFC?gw7CBaxGdfJ{T7!)^d%5c2h#xVwaZ z1nv25sD6rXHgJ6%Dj)t??&t3(o7c`2JpZ%4+kDTD(uY zAWZsZw5N|u5OgPxXEYonJ($8uz2tm@%dd*M8UxJZJ%e!q?g*NAMlBiNy=+O3+YQ_zj@!dYQn^jfgwiqA zi$M`%eUbe9nX4p~ry~+wCer%SD^S>e*pH`~HHnB1-;AZ>$n;j+3j^^pApMHzuXuJG z7`&z%i3y_Wk3Y9rM(vx8$7=~j%|Q3KB(1GT^A4RMrjv~I7XZk;VAOGk+h9V^$KHiN~j#}^KH+;VRU_V7Xep`fXaCGOgv*LY+9M7QC zEq4;{$56b56%iMP1{hhAX2eFhiA)l%$njg=oO{ zKJA%^TPOh+ZV}UE-YA9Z5&c`~_8h>YajFBx+YcjuOYd5TQ-{7-QeOS@$=oS`XGFJ4 zqDmHrwr-2HL7VW>WN`m=MMfyTt*kx8oH1!k0Q$8*dZ&Rj8t0!jBm87Nw|Lz=Rrefy}G2Hejx%g+5_}6X-*xOFBUi@wgESc%4oC_a=?26g>BWvG?fKr&oYIp z;&0AyZ{MB4MK3K-v6AH`Hni}|_d`~XB6)HI0P~HAM)~%|PW!z@M>9DQVd^mn|7z5a zgTSBU!K94#@}!8W#A3@;S>iCT!)$zj6I%rLgHgOc>bJvrRooOQ z7N=J!7lIz!;*?+f6cRYyI6oS2lGn#6O&Yp8vx$edG2~Wk@5P8d{-?=tvJEynFRk1~ ztxAg2i|P-R6F(C-BX-UQx4ym1IT4cX7wH%V*(UnCye3F--8E&>C?yAeTZ94hwZu-K z*i(nIb10L$SQUc_E`V~wX`f~1sUDQXq~9l=CCf9~81wf;e1sW%49n+DH*yi&D^oF` z3;XBs89f${cPxT9R%Eb^QEa1CQOK|tQ_$~QP`B7d>5~4R(G(||WI?7(e&33oH|N{J ziKD`b+bi{8V!-(=$f`B?Gc5$rWPPNk(_kpt(x;Q0wpy?w5q`LlDoK|*S!+QM?2z2y zmuUS!3P?!=uKVJdJhuxFB7`^`)lHjr1dAUgV~bF5>fmY&uWanHRbm7Zg~v6n5D>w}L^~mwHovpLCwrkPMagOpgeM^L8vM6rT?}IE%00 z0b-i4o6=o{p%_wr?e^7KIZV}T`<#bj?E@Z2Bh^Ot z*X(p^4ADV|7`YNxbeb(bgN)vPQ%LL#C~sl znZz3yk0Q;vk^E^W(PE#8$LWe`z-F<|AzrO>?)<*hv?(mF^z@z#Z|UJgg#FqM2zjsl zkT__Xz}G}TsbGZ2n~Ot=1=Z;L&MtDUU2hn0|8sG>&(peK9%<*=vwvWS!|5b?eY=XI z{Yty$l!#O+h4km>s<4R^^0YfV@SnBEdyX?lGPvASA@^rruCny6{ci82-3ABxgNWqncrhc|ym@_EBy% z!N!~EyC`;SGKWHyH-Kj8B%9t!Wigibn9YbO7G!cNGJ3b=Taw(AI=IkXvz0t1+yNnB zqt|w+YvUHG@fN(xnatzGRa+RfVrH)M&}Md^o_Sw#zhnUuFtG3c4Xia6k|91#cwW7~ zI6?q+b1zW(5^^bHaet%R@3dWI#-zHDPL!lC-<4Oy_iaF@!Pe+H^AS2!zn{4SE^~g$ z|M(8GgI%DQIqUl7409EPIN~k5O?@UpLiTUUlTFmF(GRc5^vv|k&s`WtwH5i|cdI?a z-kw`J-S&i_zFwX9b5l1=p`YXRAEMI!&7Q+blamJR zkvku90v{Mk;QQDnmUeovGelSlrieugm4p3r`~2tUd1%dl3Mz&4MVtUK8$SG8VNH9w zRa}&*#qG`UQ=j*9isSY$jE^l1>!Tg(?%pBWiAI_BklcuaC*6H-7-ot?6zm~~wFpMS z4sag2fh$%J^$zR`JUR7o1K(&QU+f5o1q8RjF9v9scZE@=hf`92+F6n(?*Vi{qOx~bG+lC`Mf9}!xhHY}f z5ci2cOVYAr3ZL_}WvqPb*=qwS8VXq5)}8J?S^v0dPFqk?-S$8X>_O)4M3&)G03{Ed zM~!i@UO7fM7Gv?mv%2g~jhn616xp{3l4REnoVL-6Ywb3hU`k-ijuaAm0_Hs9%hX^g z+%<9;m(6ZXR4ItqXOBCVB!y8(+M?!DZg7=1R;KbXT3H*+)0zoxblykOYxgW^y_z9U zd-w5!`Cr@~kl5enklIqZ;WaG^BToT!OrI!*Pi-8^Pq<IWG~)wx*tO+ zrbF;?Y~UQXV*lalR));Sf0n)yFg!_>0fI1A69Q?MkZr5~P!4L?T*&IajYK}9F3vjI z{vtlbUz!(#V*eJFk=L}tV&oSy%y4L+PVUV3EmcqK)_3rej0kTyv&y=!{)TpnbvJjT@KW}81;st^YHfo zWzvqt5L5!LZ2UKrGVz_zBbYMaUfm_tfh1a${=(R)T=BOnZD1U0kY>TxzHnSV_bT?` zcN(Rth(D+mIVO6rxWHW;9#kpE#&5;O|B3%on%@8|xFTUSUm7#S?&x>5k!GE_QnnQs z3Yl7Vtl?ZQkj3$SMAt}HnQnHm^8T9zATp_Khs3@Q=(NiDpLHAsrjSyR_<_5hlG&}^ z-(BwKC7wh?)2b9^+yCjN(XONMx!uNbK3Y;+-`d_Tz(!h zrGHSVEjJZ9x_=@2=S9Q{lSt5jqx$Tgn6f3U-+UUZF)m~m$UmJfkd4(VAHE9Lao|Qf zZt~t9#!d@{0bfW)5lkVawE+1qvxxdWw*|JK){Al8y{S9|#36wlQNF-4m#DcQ%E7><|sQk1cp18dDK*%WDfvf^&AhM z*sP{Isq_^7=_OYF--uR2OdbTd%vVVAbekNd;%U&ee_12i+1Z5*Ep8DB`tZ@I7H4zL zRZ(r?@`CN+y>8DfOeX9z`8;A6zwp4zODE7_t5@iT0l|2x1Ni!wy~mmaw_A?~A3d0| zE3`qdW_O|=^v%!~4TH2A3aJgJ_7T%OZ~L6W^rc48l{wsW}s z0G*WK8VQCJjR+Qf7UPeH@#R_%@sh<%;l9XdCcn;gX9UKVHcxD${)n#qnWC#3Fil(GtHvW=dNsy!uJnU2oB5=WO;^fqz6N;nc0u=3gP26P!UFCNhpqm*UjU$H1Qb*? z1H3sVGTtXZ#q_IS;0B2(`7{pyNcdojPntEozO3kntfGX_UpLI5PI|@FZxUkGs|zC! zjTQyVgo|W`feaDnbeg;DV(C_3fyGJ#a=ag8-om5D66Psn@c84w zvE4e3W{AGEW;?V;}=xb1o8&v{8shabp#Z}l;tHpJLco)#9m6&|F8Uie`a+KT zi~ryLCl7K@ui0(9X?8h;ZEMG-S2qA^$vqti@4rJ#oQNJrQ&?l^H5i>nvkVoo@|gMD zj&)h(d|zq9K@#|jX5O$@Onh=rJv{m*`p%lqo{=A)NS#){z15@H_t}S);J|MVGmA5< z29=#h`k(a(rG?YgUX<)VZ_qUvj~z;L%GzH%-ow*31+E~v3^5$f*uCM~9d>$1@2ngD+P^Cs9WZq-0~CU=aS58JzvjEASOi`Cr&>1zh-f1Jt#S z^#@ayRlO-6*5ke-bs4T&Wh(hE%<0@lZ2VcX+j>`;Kp%uevM{yl*hJjEz@oZONO^uy zn_NRk`Psp_Ca=T?aIty5eexOq0Z8QQN~1%ueun^$+wo7F#;2Y|7y`U(4Nk%{NZ%>clyCQP`Tq6qB2;JF4A&(7QyG8%Y1tr2^u~jG zp$QV{hf~_P_KMpcNks?!z8Pv^iUW|nd`x4*W6aJKc~)6TM*BHY?(v)6Q-DRVW*5aZ zCqqZj3hGt9*He4A3fxsw=R`2}H@*LT{N#rymG!-E>p7wbM-CI2ZKS${c97rIo&x;9 zt%N&cJz2g_9|mPJkzpl`prh-}jDou-7e*jL_(%&634-YP#tDJ@cR~Y`i5*#3oS)t+h-v4$+(w75fhUq{qVXHi zXQ&QZCKHkNBJ^@2^7h?%5bod!J@%q;hoie}3gDL68=#O?sm;@czmmV$S+^?W`Sa-I+*NqXcL&8dx}KQ1jjg$g}upWkC0H z7aEeVk^O6|2FZwr=3%4;yKCJA0atH66}W(-p6uTwfC#FA)(j!%@X-qAaO>!H_-dL# z3v#`=a+k!nDC#b8aj;sTBk?`Kn~UChqWO?D@EG_8hLJ8Mg=YLk2j_!9XwK&qzf#hB ziP_L-5z}>b)gaKHia2-x>==RCu%B?{wJ~YI+OTYFjRrNknK&YaRQ?IwQa?k;=lioyrmJu__nrF@7LJ-c?XoEXFZhkw zSX|-W_)_(Z_wD?dWI1!-D;wB1NaL(lwJcJOw#*#A06^xt?9oA6?Tsw>SwJUQC0cu| z&^$hNc%A>w;_xds008v5L0*xz>%k&?O_R-k())s?h5e&XHPL2u`>8kUN~ZA2$D2;yA72+ zs?v1%?*>K$n$r38AZe+kp6xg;%g^(53*3*D@8W!8U$lyil~1I^n2_I<%BBZx&ejD1 zYw06!6s<~btVDbZ>IXWU{F}HFfg%z)4HdQJlI>(&3iX=YKBvdYvqqn|!JyB_fN^N_ zDaZw8`U0`-f`Sg=O}K%K$^lBo_iEu728Dsy$V(?7v*eR^dUINV6S7fYgdC&*1g76U z@?4|0B}eIO$h1lIV~bE=>2zS@%X=@+W*_lLxh$VQ6zk!$gRUunerg2ovAApOj7MCz zXU+jVeI*tVIPQak?AU<9Zd}jidnn#zEQ%sfJJUOem;qF;#MWngzS+K0d2KstBy>o5 zFTzXJd7T5Pq?1@@ywTyIo$j*;k@a>p=4w1AG9&;9U|V1fgh88MoRU2e_6d?45@Lb1 zHc52I%&UH~8>Hr-dcH@V<7zwS`FC)k=wUVIP1+SKcDs|c@Vp)Ky+$#`!eg6rQZo)? zTm8^yq=8-&0WJ*o|1>_99yFfNxb?Q~r7jDfv_Ga6T?@g+y zsl3!kuvi^|=ZK~}8v&?N$wPOR2-nFQHle6z)_evI9;D>(0H*7M+Q?>)SyrFTnZ70u zQXi<+x9c2MvxOFO{j(0kK*wv8tx$Tw)$x28ey^<;Mjf7kLS8O();~W7MmQhl;rg;0 zf-sdd9vo;jHRfs-+uSj&MzbV7ehWuzMfF4h$%<4Q8jFRa8Q;OlDvnzQ=d*nB)ViRu zxVQA%0a7OQa6IG{df*j;Qnx)ev%c3If=OGUwt$G70Uqvb~>u z%Y?5_O0>Ue{*pAvzL#hm`znkZs+?Za!ID9(Y^D6YR0xhSzHUa8Ij_~evo9Sh1(n7= zJkuYp`?%O)&gc)g11_+Uke!*Dm2+K43DqTO6cvxbU6HD(a>ff%!lz2TIf2F|(|f{t zNV(D0s zX%JpEewvFkK9^TiDE@Cy0@m`DlRTW@>93{9qqTuQ!0RLB>Qfp)>1tGs)wDlX#}x7S~3jvVvHc?&s&%(T$5X6~ig#dkZ~T z!q;(Z`dSAvabIqOw`71thMqO%J#yq1Ax7=q*p57oCB(wVCb6Ab!&^EHcK4O>e{zef zD`m#t;3F&1i$$sz$Ptg#y{4PjTsj3Y&lc2g&16uzE0nq|)ZfoL*EU(HNVD|8ZHD&|g%{3o9|fhJeaMYq4% z6?PgAxj^x_93VDO$4C>OxCI^T{`UqA%a=alOYEiKvNv-u*b~YfxywWU;)^q2cv?cD;uh)(Y(jrL=MR}olFXOZYpw)b$J|jY7U-!oI`)1$tJNuj&F%`%q-XrFQbZvzA{#j)% zGi)_7Hm_`#4F97yKAL)+yf?gbaQeMW6oDBzy4++5-w_X}i5=g{*GnA(2cwB~Wsy)A ztuWn-wO_aiqT*fQsA(@8!Zs(K0$k)NlSb9Os}dt2@-NJ4U#h$!+Rue4H8UBwED;zE zLw4a&ZdNp^4c>?O7r{8P3oY+{LiY_@{7Z-- z5v%>LV$FNzItpBb1U)yNcTiskZFcoJpRL`MiDA?`i1wXsPnJi2mrpXAIfB&v;m~ft zB4CgUPGDBwB0Jp~$2Puo414Ef27ND%))k%3yA2CIi5g2#w_BWBd4H70G&o{;BpeBG;(O zp(WPtm5CX<-#0`{)tWzU)e~v7pF?E}5?tXomt)1Q9y}ttawIXrsrz6lPuufLBvb=H zl(X3FhN@bjTtV#aT)h;ar#ow5qd5tQ00*ayUj?C5OIFBAlj%oL)Y~YMQR5t)>L(Z0 zvsjal5B6z8)=6m-)k!4b=z+5ID%a6zVWl7bVC5DJ&Rrv?F`;RfRyi*}d+3=~>yqGW zklqE3J8Pdnr^jxHw0i2=zsVmuzK%srpnq+)4BHQU6dhRDfa!`#AF((Fu-V5~yXbXy zP0{a$%&j-VzA1l?SaV-VV%LwsB=H+l6rd$_x!6$M{nkfy9#1E82-|7C*cwFAE9S-? zK1m?>9=Qo^qJElZ5{T?Q`!PlZ;%N*}hEr?VQFKLtXx}v^)F+YmrbBZKTFT&^tftT; z2~|=q%Q0B|p-k@%T~G-tj9GrIWp8e#Wo`+7v}6Nw6{&&aT>GR#-(>-%@cc%3!fJ#1 zxgb?E6*msE`e(7~JSn&SNFw$qpy)MUXu)yiSJFKeAfk3~8ue01K~*W0RDL%`HHYtqeWE(!&sEDIAdn-O5B0$8N6| z^;m=mgliHXSRS2uA=01V(=w_T~m#1=r|nbSozl5J+be|8B5i5dxr3jFi4;&XDb!< zr*dCdJy(@odqW1av!tjSk~YNtp^c@|`#&x2a$toEVxq~WJu-pv+rXZyC+$V|iVjO? zj>yjG9ApE(ho8z`#AfKLL!d*V__tH^1Px&trM0}(!TS^otJF!I;}T-GR(&KT#G?M* zUB?1XMSbs$wYrMUZ;wIohAtkqWi0u_JfHLy)t_DCo^wbov3G^N`a;miu?kS`$@l!q z!_5b0(_a2-1DfqaF>i>uXnNx#wrl8}&?YbsOlfjqUP&PD>;J#D6vo<|;hI0gYzYoJCjJxk{ z09%_^b+ubkk8q7H`1+j~+e#U!MAIqLL`mr=iq|O%wQi*iGqMsnv zCVtBI+U=P4z&BHr_l%u=MV^MkijkNE9VW%P@&o}V)o6ujRnmo^Su>qnp+!D1mt z4eGlo+W0&?lkrZ`zE+ruM^CcEyINeRwx4BPj32LSm!Ywg9D0`K?SBzEm>wpPq84_P z%wj>E&k6ttJ)Bsd{8k+V|y3ibG5R%=d)qBKf>L#sep8W0)~w(F_j!8^42((j7_Fuqc>8!oB=V!r>m_6d#oSv=|#Lv8*3jFodmW1;+%KnrI5 z^*t3Owm@qp?|OIE55-jQ_oR6n`PU0Sjza>_@Z+-D(c0~F68&0U%;Wz0WJ7)Go>_~& zF@|PS%y(y1sJh*GSG-<2T|#hb5zhz$$mMZVv#1)rv#%lmg*;jxjs#2?&yz?@*R@SN z%LP=KjN|U8=fC)z63gzG3tRCCQ5=}H2~rBbOj`64;W5%8qFFH_{4jjW8wAnEPYMx~KqTjTN5w*L%mUjTd6&x5a$m+x5 zdA0?)SV03`a46VhFUCx###P{^MU_3D4JthWfM??xZH`l^Pj@*)`SRTc6BRC{;2Wc? z7uE!OMT!Cx{TTwTRThIuV#$v?!NFSWFy@KQ2&0_o%PS{=UX$N+%yF})du)E*?KUnQ zY>d;TKbx*Fj06x#o&sroM53S%2N!E<*OoM$ol{AxahmcmKQF+qNP(Ys4ZL;Xi zB`kZqOqct!%1b}pwXQ&v#{w?&atTbiyu!a7jBIA>ieq5hm__z4v8~7R?l;*!CP&sP z1{>4^Tq?V0uAW2|&F;oka?0O(#rAl4p)6wl2HuuXqe|evO z$CP<)-u##1hv$sUzEq1F%Z2-Ju+Dm-E1I|LXyoNSs@h5Nq)`vI)yRua)mHYmDJ1V7 zR*@*(R}9JGwo)2OHb{M4hKa_$-_qGO!Ai=AhcK0;(( zc1;@0kqr5+HJ`JuntWx#-gF#-7xfMcWV%4kl-Fe>pm^YS#k9XUEp8>&gY2|EL|R@q znk`y+MzvTne6I21teXwfV{bkj_}U@B!zPb?DvU?Z!Wan7(S_tQO1e80ST4iK#4 zp_3pbYoBRsygJ>}t}xgf`$kO=4(ua|&HG{|BYw&b?y@t3z4Aq#*u=%g_&}-NL*f&V z-^e8vA;+ZlJHZF8O%cHH)*Jwyp8M_RZY^M8-(K|Si=jMKk}g&&KpyOW5J2m5{@_`K zxG1W``e-(8Qjqz@EBo92x}8h%Y0`BZ6WR#(SxQ2yQG!2gA88&VcQgig2qLE&;SPRQ zli=fKL^`$ENPml@cQ$IX+MlVO%{>oN%IOQ`@B0ne{~|dVax_GG-NmDru9g((R=B@A zNT@YXXzFlHV%tF~s-jr^ZT}OGV$sT|C zZqome0mr3IQa91>=E4T@eYp{@exCW24{~S%oz-zHk|XsUYeB+juP=|tT?>+wROg!+ zIierg+K`m6rBI+l%z2%EweHa)qA&0df9DZmFv^)MYV)~=l z47*Iq-ph9Wf9M z0u9pN#gm@E$?Go^xSVlh$)ss6m^Fz?MJ4?ry*5tH#MHQ!y~C4g2dpvu4v_L(Piar3NeBduv##{MUZuc5 zx8BLb3FNVz`qfyItSs{iIxixc?&<>*N;P*3Vgw``9>rQi4xU7ZREQdH(%S|O!)IgV z8h^erA7u#CptZ<6`8UIbV4D#OD4yivv%K-)^u9Ygj2Yo`Tr6u}^Rfp+ID70r&tH!o zLEyclk2qeA1*O3p6bGLV_HModIj8#OZ_I9ImcDdIeaqGrjUU$Dcuhj)l#X4H2^-QV!TZ{XMaK(nAoV=?M=OcC3d zOvtFT@lRf$P${z{^8h5}0+QJDw~TJm9XpC0*Zzq3K42rDjqn>aO7IK&;r70~HSiH- zz;*|G6Ro8Bs`C0ko}lHLA@T2?CWYRVP{T;bauw$dQ-Bt|5-YtYnu{+Igz@Vj4@ShB zb|_#V*6e-C($?ONVzCB0pXHP{TuBjt4Nus1XcVgnvQfhL7e@*_CJL3QH{g2pHkr)4Xfb$1Z9Nf7B>S8Urd&m_3R^Uz4LmLr*JxBS^CGlX}_U zYBgeW-=?iYbr;X^6Y5`}S(|=YZ6ND-I(pI1(mRVq8WXqrw z`l=#IWVN>NF0b5B#4r8VKzZ^!VXR#m!B8h?hZHKWrp@z?U=T+*4L{J*`hXYw) z6gWJ2M6obxB&hv0{}V-WQ$cgKI&wMods1%8Wsv0c9w!$((hYH4*|Z+b^1GRys4JV^ z+=YM~fo*~!KR^l5T@)6d76cJ)Pc^hs=2{#VH-fhLHt zw-Uf6^nW{iD7`?DdKzt;E8tQ*yBxf@uUVo|{n||Pq^;}4t3*1ZHc!h1J1#H3k90CP z2T(V!D~<9oR~{OD_AfmPza{M+QfT*x8Zg051jO1|qk#9~;oR>p@dz+FSPY9{*<~P$ zqIiSSYZk39MQ-XX6Ke7Zv|^kvTNqj5o4_ayzLP;U)kRLai+2<5n-TOObKPlrX<2pq$XocH%to>+!A1-2>I~fi7yBbQ4{<-%0U^ zTm&BUA%f;`s9{))e0KeN@Vy}1QAR)~Z-T^T zBKO(~l4QS3n62EvC$^5(F_5z)|G6|M;Mx6ks(sE4J)On|3l`Lj4xCZ?r$rz&l^Q+dCY<&%O?|&RRdGzDLc>&}qjOr^;q5WW}P=Y0OpU$QVt`Y4 zVI<)9%u$J_zAW2**J0toRs(WUMRl}CUoG|>5-}N)#)+_~s{HcEeaZ1wXnK+$qVF*P zmqr4KS^DXvZ29(xqCuI(DZdIrj76j+^qfeUSPmiS<3i%W$TpI76a&OJaj^& zYWoilwXqb0w&ZDEn-!oY_GGmR!YG9>+GcPLnvttI+F$l{kuXR-LQD@Jc2hlz@0;Rr zS!Z$1a9FRXak@X&P9=OIJ5k!!Nr^B+%@1J&ke?QAC)6+71YRx9BStY~Q1o$FNgx zzj|`NJ3D!v8S$bAG{{QoXC60Mo_M^)HX4KnX#&*YBG(wBTUwz@%K3*Zx?Ei-ovsi6 zluY7Ff$N>fkq471#iq)1RoZmMWy?QJB=~(!QsX)|K(@)e3l5T|f&W@M&|yPAxj1Iu zdl@q3x>Pe^13$>6CI~g<>ye42qBZRfR`Th1Lyt;<&+mFh0XJ&;-A45C-LsRu0!w`6 znQB)Or7WQkUC0n`CHL6or?VfQ7#kH0B$d9Ai#|D7U6f_O+uk#z_iCkVTYvT~NJ?(z ze2*nUL@iwA*>S0M;GW zI4_WXvBlBJ#Ha}8SVnKj#y`2Q2GH@6laI3K!O3C(s2H#LuFvni!w+b3!F=g_-(%JN z)%Ij;_|;yQXfUhR+gRAmbx5S2kp2UftM+qrqy8y}lZ1=Fu||KjocZUYp%@wAkEnBn z86Zn^Qig*_t$TD7cR_SFM2$f{Z=tW;8OWCu(p~^4B12M$N4Umr=I6%m+)SKWNkFUW z`Droe3>ZI@+PS_0b&k{0p@lauC_xgU8vyN2;;91Q_ky#8TQ=L)hp#dH2T+ZR)$Y6P z&a1NFkYXxN_R5gM7s9Six6%>~o8CSI^qy#+^L;vrtCNkf6>}o?&r=pEEM=P5;Lk-z>0GynQI7rXDs?C{JSN;<%6b6$C6&oY2saq|ecA$cK#ZD9Q3xXuR5y zzbF==6!qq}%;SJr$6u0%f28nb>??09Yrhn!}ik%@1w z_d81yuX>}?-5tX>XU3YquL3T0zj{F(@RSoc9;-6-!y>!5Ut=*E;rPK9GbUSYZ@wc4 zlZ0cd%6UKP?wUB7jJIpfk*9Cgo&32&TiRlA@U(yeCp`3Z3Dxj(Co$3bcr$~OTQeFe z5#OSTAJnvXM1j{O)&2WNldRg#CmWnMjqc=oMWzEpTdm4o@Ed^&!`2v?Sn6$0|5)bg z=G@dzfZ3~r%se9**Y$}}_Vc^a$W}i-sE}Mp!Y&Ur%2cSp@wP7zCG_Bf z+D(G{_T6MV%y|h?=(83jpD9TER3QV)cq#pABFEpb&iXbNuF9(S`8f`?NFD?oo7)m( zjt;ykmAy)ns2P=|N*ky*jriz*)mHRy`W?5=HoQ0hfGVcre+pV&bxEU!tWSJmR9YDo zg)NtIpgn$VAH$~KR-EAHN7;8Zwq=soxM*i7^0Lw;%VwbgMXOS`keqAEjo=Zo7P1?~ ztu~KB@pAE)fUl%2ez|m=EN6$z=;$e%Ow2uUUb}A`++VCeb?{_|1xwAy1ZT}}6Cqbu z8p-@Qe+ey6Lp|qXQ-hu`XMC)DL(q=;cFIZ_vbM!z`6^4qucQYyk}WgCRS?fD^X}$+ ziFZfTN#$n<`zGNn&`8Gb~Jp)0&6{O{kiBXE7*r_mT{lbP>AfNnVf=lI# z0<+yh!@|=MZ?$GMhU2=oGBK#n(}+PuKoTE)t_8S3Y&lGpUr+WVZ!)q+bHDvM2Hr_%kY(EbC_nKQtZm(T#;>WR zktr~v6~b%JX$T-=_m$`Bx}hB2VU2!ox?}#dWi#1guN82?$O*KW?*!{@X`8u*fnz(B zG1i3|>(EDr2s+0_p#k#CR4N$XL|^TVWILQiPceO}${9CSIa_3+@byRfYUvx*H|Qw!l~_BMnQ!!Ui(>O z9O{#eiYZ(4LO|Q4NMz9(QwoBx=@b#e$?I)CaPu_}PoR$t)H~chIB4a*nR7g;mRpMm zqZaLuAR5_u`(4&z)X2|nt(hreapkz2svgSVkPF)z<{C**yq_U8-EcvL>BU7BN2{8kQKQZw2`OO&9_ zoM&p*z-@aKUo!NFY^+^pi(aAA3?FuZL(g#n-8#DCIi*0<3 z+BWjZ2Rstawy{Q!5_56K$ zt%FY+&&6XDQ>%Z2%^rKxX|ctEx2HK4~CFYod+I1AU=Qk!{^c!{j1 zaOHk}Q6&FWpwc&y4$0N?$%uiRDS164eClMgpN^3QNB=7nj#^tNM#yT&K^9rIuVI(6FM#O!Bwj8y|L!T_c-nJth(@MlVh0J%81ggQAcfZ zp(;lK)H|im2PTeLqEpU)nkJPkKUaNJka#L)Xu)(9r~Z;L#Md>mN7cnyQVjb({myl? z+5z*S)1n(Y+8R^hw}*k~gd3CUigQttD~~=yd;LkmmE+1n#8!bKi@MoYnD<jAwomI&8;zOTHT*Ti9%ODWM4BDQU4q6}hLt|;bHbM{IUeL4+B`yrxFi!rB?Y;>i zQ(0&WUoSscyzwA-N@Yy)Cw;5M{Aq`1i(Dc3ySL1}6o$n;B-D%It>t&2kjnd_op%SB z@*CCLxD@R^q-c)U8_%KQAN_q``Ovea<#QpE@R7JZ=Ys9Sq_X$ZQKBp75UA96>(9ve z8boL|jym691=$@JuKRtGKRoCM-(rYaYJbl*t!$Qcu9R*oqX1p1r+jL&mJ|l7u&tO=C$=-u!%~k z%RaGvDYDQ+Suj!C?9J;8wNA@Q9cPti7D-~2H$%7No)LO@(LX4rKY|2WSsF%f6*k`4B@=82i zv+^#8ZQ`W<(|JYi;nkrme$ti|PoQb+1fAVQ_cKmyKi}`qU}ETCUZmjoRSWkpq4m9S$XDtW zPfL7VQwde4%fQwm6- z(@s`|5Pfc9PQ#WVOzxxBIeca!OJk4jvpina+FGl?0CXEAvg&&MlBTxxYJ6h^rFJ83wskXoKXBwScNA7K|ZvK$p2-%3i-72HZ=dh5^z~E+uyl<>YoPzOi6V<7n zMA;o)&59=DY`utqk2S~sl-0#!3QaKn>SW>d`yCXEfEgx+gMy{j?#Xg$%u=tOeO8o_ zBu|IZ>X0?j4mTg@G5&Xm5aB_S9}s*y2sOt#;;>hnnn4^441ArbMHWsA-~Bc>$e8}} z4%)(L>6oD(OJQ3mvHYR5?-VcKGz}kq`RnQKp(E45dP%bX*(-A*jjTI?PoKy8H;9_H zj!cP@@hP5ORJh4Ik?Jc^`sPqPjD8RrUr6x}ms$)RRi=wBL0I?zrhUBB)AF^&x#{>9 z?i?A`PXqqSOpL`iBBSsq8ad`#fkLSB&>~*UHX5Vm&$au7yW_P>M!zEqyB#WfH==z# zSM35EaoK8>V-5%0Mq@Q`c&P}Akj&cIO%d<`;*&W;6%wDJZg(Y})QbM)-g$PBB|-+{ z%ND9K6+do1*UzsH%JQpRe3~oRTuz3Ka&}t)`vX%rN~%h zTHbidMEj|;RNOq`qZaL2_eMDpNNyMYoK(v*wB?a4{L>ZIyhRD+_gAvLCz=tXP3MQ? zwOH z7l*hp6(m0CfY0uXTDS?Ibt>-3c{dvhj;ZoXRVb8D=xn))apafMu|eK?^99?k0>1e% z^jFJMa{n>aolD$jKOdiR5s$+%8}BN}k)^M)?r%MQ^}mngL2A@KJENb4Rg?(N?n0xF ze-1D^`p%r6%-`sdVr*J_+isuShhhsX+VM9m@|RPtz3qnadjp}uNuMlX67&Sa9yH_W zZoFf=qggX<-DF_9pZ7Y6a_XeFZuegV9ZV~6sV-=OUufIp`}-2#7oKVdpk!+A@bgAw z@wr~kKh>2(O;^@ougP7OJz^ZZ=P&us!i}Iw1jqmd9ln@LC1NE9yzjsiB|v6SfCQ=e z|2JD{@ecU8{n3S1Yrr*+khT4&H%@5@M13*LNy0*7v;K5M#1eNSt0&pfZ=fO@6w>Y4 zi+=XXoIWPuSYh4&`tXe~9j5A8)?rpb5(3EM`usXCQJBCd^&I3kLcXyWCA5dr%OPu= zHIY_zTg~%Ve+95Lt=vK1MJRyTdOO97|86pfrY$4X#D81*5B!@*YMkC|cEcKv z@fThMFXqIK1P(RTj`NZ~l4kEI#1OW&l8p7xWbS7r6-%;=B6bU8#UCyW^&Ge zXYO-mLx8bYnHtJpI4ZuYy4~T()ME39kKJgszaX26wPk>2^xviy;)PWY7>%+;li+e- zth!>L_tQT|O6??13IEsX;7QCGfn_$WS#r9+oWze-Q#Eh;1h|bLM}ei%tj* zTc*Ju1ONR8q-nrwU#wq>O;Gx0hYS`AMj(#Q#rqK=fWK3~7TmKxyDuZhi26?_0&%_M zjLhTQH~+0EU7&z(jmPdeUBO>#3~(QwDZn=AqExv4-BM_mXHhd6iehZF)&KWruF!?F zTWhlf-N}HWZ7js|Y=;!!E}K>R9{{{f%RQX&0^C!k&7C#*VDa%Du=Frc?$Y1f9bo2PH&Nf4;p-*Xy4DO74 z3YBN`_3BxELzZbA<`1MYXX~9#w|GwW=8UZpfktb&25W*x^~|)JA^g96Bsf+Kpb(rc z-&8)o&U_%Bd>2$WkRWRM^9^9AJW|dQ`dSU`Q!Q{QIIy7VHUuF0J^EyDD>`LhDDLfZ zi>((FLT--_+uKws3`pBfExA7{WzG(n%p4KxG`-~n^1Syz#g^+cJ+l6LwPez^`t3LY z!WAr)%TjW#fjakXeD~F&cBPRih-P&<;l>xj-l%6E$@pvnknbO*dyylZMfFBeR`yBH zLFRkIlJfDwc#-wta}kNay9cJtWUK`7@cKye3c1ey7$1;49#8`}gqwq}615o=(;i7- zd>ys2aw6hgJrA+qOL!Ul&IH0O?q5TxJ7U{?&Y^eynbvB}UfYk7SS^;W@^L3qEEMhL z8c=-Bcc-VV|70IRI`a_x%Q7pEH$PI40EIfB@%+Bu?RhH1tpDel=k+e%ApoHc$3}7K zIn}nGRP(hE)+_HP}T}=qi zEZ_pD0#9YX_MEM8k6k$FMbF#S;jHm4jyr@}^H1q3l)7%d3evR%(8oB)8YeeGo)>tr z)WW=xz-fr<&0rESfStIY1b`3lA^nBJ+YfYPVFg_1e=TJgN462n!YxtYD8mRcM`H8@ z=+>gws751>owgwYmRw_yCdhEj8&nsI#$pDa-RXqO3`=(<@){CB>IDtCC7XAh-lrv7 zxuR+VqAz2pMFW8>b}QC-A0)5wS+$D~+LUw8l|4z0Yx zQ8z2Tdua%Gh1&c6IeZ;4k;JT(fT?pE4_5!69b`T2iBTvP;aU_L59?emul1Eh;; zbeXl&A2&&vNxuV3^oUo{rW@1aNu%OMd5C_lv`R;bq)l@y9dz#b{8(>sHe0usyx8Ls z-}7@DD{|S#Xw}{|64Lh8yX_P#`?5M&sZFx^v!EyTQ{e-$G#9OM6uz&SiM5#PJ@>Ib z;8Mo`UQUQk3xc55hjUj=2-ss77rChj_Sk$g^m#0x7MV_bQC#OaQ}VysWIXl-s^g|o ziny}w7dxp{XgmW+~{X`ai*hgKjrVQk{ESe?33aMPCphDyT;RG5GBQtc|p6P2;8X0EaE#2K_ z>p5={0hIYmEdUJL*(CtcEDrcgK;yyY6E7F=@gRUrF1(EP^ET9|1V=rh8_3Zb%t4!(eM+ci(*JtS5 zY%N6XXJ5Rq`#q*nS9Sx+wVIELc^w!{wR=j;Ody-wqPEZy;b(Bamh#(Q6wXXDl~BqS z!S=QS%iPZ}47WDV!zT!NH7J%#k;-kQC7LH->OPO|79@#ahvyLcCn?+$#R(QwXX7gD zD;hViUWIK6N`cuk=3wIZZQzr>z@}l}CTntl4e@YmWu|CQ?Py}{$B0tH2KpF)(3JS5t88gLNrPlW#?w8z(U8E3(WxJ>MBzYa5NAO0tH!b;DM`>(h?$4w^3i z8cW!>`Jt_&e*s=3onqnieZdBnbSmJ#gQ`{j84vA`sWFEfbElSXE{`y#Od@%0^Kbc9+#i#@FSqLC)|SFS~^n&GdaB<9GN1 zmdc}ASC~>2<5Gp;%kp2K%ylH-LTxhOC>Le*=e!E~rSX}trO+4@koIHE{+{InKDPS$ zt{<@+bC1b#bhE|p8&?_$(}h!n04Y^YH?C6C`g!FYpCU(OI*mWFg&&5_ZD~jvS6{3q zf9LNw$#4QQvAd3~yA^Zc&)*LRFAm$I26GtfPKs8R@1pxkXft^g$&StVj%R z696MA@nrxetA3WHwZ9ML7p8pe3LCI~w9m@pmpGxQ-qAqz(iKQ7fRA1E`8Sw=p+PiV z&w8I``yrszMS=rHQQp;{1kY)p*)GFGhKTpc+dI_CJGGVC>H|=u)pTPl_ji>k%3Em& zf{bS#&|mYW|2^Qf+ibs@pN6J_j~SI5P2vOAS3u=Btp!E{7N7V+?*k=zekii1DNu-| z@H^+Fez4e{uB3*acizn;e0r$!1@HkU6*s!8L$-ZY*`AuDrPPgU_ zFYa97ROa$~^$-ja$)o9M4Jc2g+)4LWnYP37li%i*K%=Wy_ck}bIKY|;=>2O&mTE%G z!+pvc`LU9jRFQ$tz^e}5%M*9r2Wfnc4&1|GPkjW(RTurv4gEd~++Ce+3)nv+m0j~b*-(uRfqh68rsLNV^*OVvmzWmxYZpVhYY#nr{T!0Q zIDGixy4LjTp@%n|TU3vrOx$7#*iLXqJVL_ZsmdVo-got;QWSbI2Tl`@L7m%f|N4vW z!t4j0-07sU{~dD0o+Co?^Nn!{#Tn~LPL+5UL5fTmQ%0kbg$+8aPTkoG5Mg7#lbfIQ zp60}8O!3(K8Z$b}@b2UEh*)vs1NFG8`jlOTzqbgWC*A^sfgDhP+xztA^h|o;CxX7~ zzG!kZrJ4NLdxaH1H#s%&>xhRMn}oB{UvI!z5Not zo2|Fq7K*YE5f~ZGMH!*b>4td2y^u`0ugLSmf5pN3q- z0dkuE#sXjQoO~>l3tIqFEzRh}$R^vK#ZW0e--#RNtY!DRN>x&$^P`Q0Rz0xbgd z?kv8(U(F}%g{w1|+Vk?ji2`Bl(Qbkpip$TP1L{uC29I(bwr~>CH0m)7;pyG`jh+)k z6^g$h`6D;1vg1mQPmkXKWaIvgOX^U~LU~OU6lK=z6p~#v&{!6g{ zJ12a~-qgs=$EMnb8ZwEa(nYc}J?j|nVuIV>Rzxa)@>=N*aaT@jhwx%xnUYm(DzYL` zUY2!xo(*gU^l2XQpN_;kxl$$tMjloPWq8Y&3c-H4?g_JD*cCmNz-t>JzH0i#UXJ`E zOGfO`BA2gxe3S$5Hj58BxR#V^)3U0({>`*fbb`}<+sCmmi{$&>- zhU*#;O#1I@*wFvmfn5mJ6FJ2{Za0W%`4-4+Jvu#Dc>Y>QfSGF|0p!EjI0FCTm9)$L zAQWs}dYMS}Uqo6(3j)dqp&9>8b0<*{2`=ns%0>S(NMh)}0SU@6Na7zy5)j%oQ6qR+ z=Sl_A|DhRn;IWNgX&L|fdmg~Hj?UZul?tG#c`;p@OK7U+&%Hi^K983MaK-1`#HbLl zA;vgb#g8e*4~r4et#_;5*MH|E;u)Msq_rNh@L!Ug6VVZaRU4{#a@6p6x> zOYsL5Mf~6ptn!+omwOcO=AppV2cgE$F4GD8fAtvi&E{F$2V0Y@h9n|AaPv=NUms2Y zR~8x#YP3fAgnvGj;GnMc;X7vGx|ww)I8`i&-wTzqtHV9cUK?0hZLnObevJkEWmZLC zdtz7y$}rQ}&(?X~-JYWmyAC8U7wJ@+<#0PU7^1X!9gkHSi-uZ1zMOOHTmc$v z-s%65YNT@U9)g@Wh*JIE_5y1NY_H>WDd4$N?R{$V=0_ZoROF+{X$bt%>V@qT7VsZ> zK2fPxj{!m@zR~hPLH8|_;WVBprnb{5eT4N+Y*MsgDhjHV)i71H(rP=Wv&iv$8nPyn7p z`zfY$UA{9ud1IFTXk}Bm3UDUgg9X?iunTzOAqX}v>{K|!zh62JC~w?JQ75qI zJ`unCF^q6_^FG}}0|XRaUEleRd@m8NpSXbUES8)?(oKq9S`(|E)FQ1B5N?N2ETjK=C1!D<1M*VY*nIQON)1ciTvo*Y;F7kkV^$$F#eoEnlB(n)hZ3 zx)0Rd0~m|+d6R%-mHW1qeYn#vsEP2q|5c8Jk#JBUwitvZRwLg2QfKAxrN-4WJ~p%u z^zunV(lfPt3bih4a+$#^NGK0zlrs1Q7auE`_{wHPS^ZE&m*fS6^{EXbRmnuZH_7Tp zBmm0Cp%i)F{|V9!?7~kOaIibQFERXl&c)xO9^&&k7|_dSVKFLas8Kd=dBPU%l~(#0 zB^^KCgvKQZb90L%SvC2`VVo{_Eb(B@cKG>Fu3wy&>o=-Y8j0;MgI(NG(3VC%>Dg?Z zLv-zjVyE(>?aEFwV1}YoWfDlLXnW5B43?z{sxXEz=bK^}V18OB@;g#h ziC3hoJ2xB%sy4Gac#OKmyRy1~suhSZ$#AFyqb^EJ4gbZbCVsl_&blk4329>6W==!{ z&HG@UL~Da!o5O8q31=%NAfR=NvT6lB9rAX!&F{E^T-{u9V?BPM!=vMOO4kaR#VlX6 z4hJ8<+4-I@kP|T`v0tMBdC2$A521MTt~-M_ce{pOWg3%|BG3K=U4)Y9W?|mv!6#yt zuS*AkUZ92zn~tqIN(1MS%Mv=cz##Uh+CNgt#s?dsr?WP~qPC_YXM=bh?gY;x780+j*>F2F8dj&(p%1vX?w! zTd%XSL&&GBrvZlpe#id6xpC3IFx`70q3YXB7e{hy*A>2q?CLy(MShIF&?|Ki7XhLcvjDJ zYN=noD@*5hHe&(|d(9LUgkRMGpWSafUd-N8GYAM!O!cU?xA4jugAS?}QC6bvPffgn zKc0bFBE1(zZo<#mS!|z!glFL!L|p)yP@ChGp1zE~s6V1_DPzQt9g(>r5`6I9_mD^~O%(qhk0 zdHEQ&KmnIFnrRv4={!wp_5P{3#{)UO+8EGuxPznY{j4b!$rON@i~cL6MH zHFaP$Cq(9? z_ui)`e2*lF+(9ApE)DLA$*gP<_NUt!_Gk0;v}SAb*#9)Y>+#I_?*9~Z=J8OqZ5&66 z5(X7D44y$0Ns7rfB3osP5JF9iZS4EL580Qr*hvUk9=mKQlkG9KF^lX*lA4%d?C;V0 zdfxNzxzD-I=RVix`rP;Lx~}g{m33Ib?RD{Nh8&2>P0#?Q^Yw}Dp#-V69V@u(_*y7O z7eTgUhrMvG`-E6svp2~{-u>f>$P>vU&BzCmwmqjPsXjQD2HD9q_DbDR|kLJ z+En$>Q#=xF_xbsD%_{QwQ`T@FO$PbOjsWUJ2$YsfIS3kg^DBlx;Mvps#tya?U)hs{ zXZ4HDRaq&Wuti5BNNO9lzHGLpggE{m*R1R8Q!Uzqngt(JcurV)>Iyw@9yyi@l=diW zI!>&AEbaRz%zOt?hO0CGBDY+2N37-VZ`OW>hEE*WR<&LSJjIHGdrwaj0 zJhm2$%%XRVLs?q3+sEGp*5n7HoSwzes#?NfzqT0nwLKf(f8CubH~Pr_J@PWdozz&b zq`zn#QXRu+0zb$(eG_+pvJ4uI?j=l)+?W{X)(F+LAJAK#nDkpNOo}xJ0BAz`DdNmf zhKfPYK?wB8sifS8T`|hpH>$|}J-DL7?mcHR!^)f)#v16_6i<@xd@Pc@?3Eji1p8l* zXM0)P`TN$FTHF3w+E(E(j3@{X`OuxAay*X*e9q`2lIKm|86GAXro_a(kJ^ig^7}te zaPWhk$vk`2Xj9X=htv2uHmXMhs;)V2(k-HX5bG7~gSJ+u_FmXb?3k401&~aGg|X+D zRSufh1+4J-T3u6T`bLM8R;pDF(py6Y4C)ogi})d;PO5U6R4=l3s+zs4p?y$sPA=&y zVg2VuM73R>X^fKdz&ydrrR`rp^wzz0ubv7q~hT8BLH zAO5UdLR0TdQs4>q?l6H}iLTe}w^@zj8E^wKG&=s>IET}>UmXY5jk{fEXAhLW>^cEh zKo(_X-nZ8}JQvS$48?SQAu}K3mkKXsKRQd8XI(B2>HYyMB+~=;n}8~}5Xj=maJ^X7 zfo6?e(mP3wjj|y=(>fLBm6GqiehIBZIt@)>fI`#+be5u*xs_^?BBUV|WdKm~YS7Ku zm;8|1qvyKbDmW+1UkSJZzL%$>d>t*y#Q!}0_=GB>1HxAsQm^>rQ!J>5+)A-s+7z_e z&WZSYlV76ERG~W#94|i|B%7j$qtqw@2QmuGmIYO?BuXRsm(p3o1GqZbsk_Z^58o-8 zk?;7MUug0_6h-pVV6#N_xtm)Hn(~1-YV|068HtNo1Dqn}5eB9kVS2}TS1oj(9?dI% zlfTWP$;PEtuQ=p>u(%kr!YRfdgpZrBx3sJ*i_G}pP13&cDcB5cV*1OK<5`<2E23ol zOIHNksrv$*ZJy1Y2%A1mavW&u!m#-e`hQ)Mgy*mFC`5++xb;$BnU+DSb4U-Ii@WF{ z&8A=1J+{#wVq`Ey^>JCuj_?~)(d!Fy^MyE3gJyzlZ4p_qnh9RO- z3e?dtiIH?m*abB5q?;_uK6KWwm7cJ1lc^Nl0Eo78a;{VSnWvlFu~RUiWF~&MqOhU> z0I)Zd!)Vj)g%P66wr3ha{M&9&OE>nFtD?8(f6=qXV-Vo9rKlS4`K1{^*07(zjQbeF zX+_27RM=U=@b1@X${jMheXgPX>=3U^i=Y*OXhDGz1F@iWa8sFb_r;J5zsE#A>5N;E zRKy@STwTOBFP*DR)SoEgf0v5;Nj_+@QitZ~QnWY=G2|ORjip;O?|IJ;*B(1@TKrCV z%W2sYW`DEDlrU@kzS9kU5oMZ`nmZZj z_w>p(bAh^>Z0FMVdF}ih4I4p?3r+4D`QrMvtI3_isvE1x5dk13EnX%%$8`JN&|``h z`4v(GS-hr_dU0no_?2iNw~`J-#ahVs?lx66LJKYuQZCgyN@j&a2)=h}F)V;9>7Qcy zYe&DYe$PMLP4q#KHlk}yxYOHo3w2SKp(Yz^OD*zvX2So6lDH`P*B6wZNb#OQ+K3fP6%}1&0=>15f7J=BOm+bAJrs*6T#PbYzY!CtJ7wf%_95da@i{FcA6a|dd9b-}mnBd5N zrz4C#$we7b_aBDOGj}Ne1NEtC&|0-gry~;eeOX0vxW)dKY*nN%5(jz}es^SS2wm3x zQ~dZxH9@K8e=4c;YZ$xW&*$Q70bj|61~9{(HOe8HBx1ET_-E0EZPJ{?>BQZh13T|+ zcX#`The^XMF6@`~L2Owe2<8Z)=&OF6L-tCq^JdGxUMkIvL^)3Jr%;w(R1%J{ihatz z`p>f(J1v$ysAaq$9o#5seU$$PeF2I8w(lu#7b073mmX6Twf*h)H2D<&;3&B?*Iltt zpYU~8x=sqfTy1XNZ@UbT>{LmIhF9@rZ$YpNAWFwz?FS&w#I{%OVaz!)6qrga@b?T$ z?uD(IKm*UHrf5GF?WxGC<=mc*==ki4>rQ3-bMnU@ZPws8(>|sj7YPr(6sP#PCZRxs zh&|&ZYofVvFJCjQei_HT56}m^$ozc%b zo}|0xRF=T+48EP9mZh*Orp#7wvvNox&_a_$uI5;ONCwhx4ZcIU${n4e#mX|q?ETXP z%f5Wq8$ZU_rZ2^+W8@Hzz+iA|;GA{-jiBVT+pJ@8VYnYF%m(Apsu$H6oTx8bq!YjC zP)#C%gJP26rnc!(6yY)3QF?>WU2#!TjD3+O{4oWu9J#d0 zAZr+BSNx0?ME<3#*Gvd)f9 zvL^&c30s8;lU$JoEG#0~+&u+|EENE~K`kEvvPdc+KvNlSjz^zF(FNdY_5C%)TLnm_ z8+RV1JONC=F4j&QFbTVP3Aq7f8JrZJdcQ5}DyI$jxkgBb@H$qV^YNppG#^L}#+_Sn z4zw-ey)DV669jb!GFwW;IzJ@@c$7W(;#ZA>d)x$YNmcRfhkxgAA`X|vahZFVsJn3e zbgW@+ElRSAotk(}yTYPyzb(-2Ik=ReR(E-Az=M-FCIEC7S4YTgW3+krjst-`)1YsC z6n0d#psG)7JE)aOD7s&<_GC}Rpn^nVI~V#>i>P_P5Hv6=>V#_bm^h-S+DL8WqD(rr zjBsub#)-OijwB%{bL67|BL*2xv=Q>3wFgtS%?!wOeBdUXMU}3`k@tsW_7Qy zlKUQqrxCHo#x$TnFbfe(#DW^W&ed<6fAOc85l~;ThOD1HIRZCoa@JnG7@;dAj9wWL zcM_FJZMZ{W%u-h@MxFNQ)BlV`W+(GSZAn=<<+(c?MQVXWhPbRf^E{t>WBwu8f;->3 zdnyD;lztJh(OR{6yb^ItJ5skJ4YhvXn=A6Fbc6ci%&GD3dq+>>9KsCW7E%k+`hTX?(p65pdIwIGb#*Q=sJDhyrX zNSPL`;?h4On-iA4o1Yvb^AaS>AIz&gMDq&lB$RldUj5%54`Z6gyTPV`?K-F70S)VM ze3?_<6OG%iMKv@n(JD7a955~SUr8mS=rz@Quq#Kgt#ekhGtK24%EAS;Fp}(DY5U{F zDpq=omQq}qg)H*S{7lUJ?9-=Jkyf32$N$nF(gZNG1}DQ`v(}H9Sz@*&vSb{s(rN3? zWRo#k8p3jV8`l$U1|K3HCwcVD$vIm#9QkJwV5xdl@oZy_5*TG{VYgFmzm)3u`I({G zq+XlK>ts@FOUC8@>G1iZ!Zy9Hd3iD4X#|(?Z8sjrcWtn9J0I{LV14m@X8$^CXR4}@ zm}?-rzpcB{#<1okJJNfii!}G3ll)l#H>RRmxutatlEln34)QY8Gko|pZ%G^EAQg;DvykU={5Mr5z&fUe zuV28q>qtFNypL6ef@1Ar2S-WTT z+P$W_Y}c-?`g+3UWyO&`;eG-G14EMdA)){V21y4727U?$^D)EpNd55*u5T_ZEH5D} zOf2tUYhrF?35(=R!+(L& zktIuST9L?4MV6$FOxzc?M;~gxPI6vnMzzg5?hz%&X=>^9vr2umFw8bg*g|kBj3~Td z2}aviub{EaXRNCPWq-5?dKm2&pR~azbKqB_A3yXEcT)2RUO^H{ywp~H`gmV{P5$%~ zJ}09_B;O4))feig%I`xrXk*;C1rf}%o#BMx-OS2sYodT3Fre~PSq948WC?F7nEWbw zu~M<~cHv`~kuIF4MgSZ{1&0nXv1>-K1qsufZ8!E z;9_?(Oc@-{=@;U);#+s!eV0!E`i%PCpYJcZny^a;4E6++P|?A|$AbN5?7Bmgbqf$v ziU@g(r)4*GcO@7TgQNdv_{)>U657XSH>R1y5d?ItaJ8MWBwbTRNsO@lhsa+91)ks@ zNCn!8E}I#>$?X%qSM>Rnc&+ufMmQ=enJRhAaHAOcLH+pq5SXTAS}k(Lf^E#+W{KpT zjPiATT-rHZDZa?wuG?7QbL3ed6M*>pI3nGY(Q{iijRDveK%H+-tJXKp`lCbKd3|e* z+FrW;BMbfH$m5k0j`0IxJ*Y(Gsz{a@Wqn%N>9H2}Q9GE0@uGMT(6mOQksU_Z6q>WbHQS_H?bZ!T)X?sZth*pGTj9rGHf2hrDW58US8lk@$tl7 zabbB}*=dpahpc25MBo*64~%!6vCf@rk)KUgI%Gk7j_e6BOLst7+rW+Vb3+&`I!#eq;^_V*fX_O`xT+NnFU#lP}PySb}fKRVCp{Mwa1 z9yEsg_|>Y}JGkm-l^}vMRl*eIB+LB0(!BEWzj=8P@1ptq7I8~QEbUQQrH^m9U3uBj zv(I_5OgL}{y)XA6(m>E!Rh2zl>xv6jsL;|(MnL*acC*a?=Lc^XOc1^J`fKd^m1p{{ zE9cv>HLq?MrrImLi!OCPQs_Z=Vm!Y!HFr?&nl`29SwEy7z%{vYvC{r+z1>3bclQQI zzmVyILrj@+j~vPI+h z2T$`%g>~uPE5I22zpa+PNZ&)P!XqS1pEgvZxd5!U&rT8>M^7*3d1Cu!T$Z=qtJ>Vv zc)}qtVw(7+#QG2<&BhH;T35vIqyD)#y12nfKTFe`G{YNOqhxTpT9PWnQZB#kt66Cx zU7GE*u7Id@+Tgz=w4foIM7agE)2qZ8AY~Y?_N!mB>7U^0r#9h7W4}@Um#is%+Dxg| ze<_^(OBe3qJ`bxQ}Zu~g(%R)3bCf1MN+8A*p3O-@ILoCX`1wF=N=XVjo- z1)QfOpIJ(Fr2gP?We`O^mx(RJ2#@cy%e2zzlp8u@lXP!p%2sMerE0G^lyK_AiV;fg$KRYC^&6Ce zf}&hWCV%I9o5nbK)|#W)dp1`BKLP)BibMjs5_zPWKMYeov@^@)Bt#g8|Lyr#=E^l_U*>R8B4iJidgZP>rm^&Q;a7XPTAL&D5+C7 z+7~n)%8R-*o>D|{1K{Ur>b3q6b2gLw6h04`Vqjp|tN`6#Ue{{gl*vP=m;?GhxFHc4 zZRU-%rel(`Y{wAlv7tb=^jz#qYf?^J{8%yrQP}V5BVuEkJPC{x#c8iW-5u?=I}~ZJ zw@T)7)#ZJAG4V>lH>XRVmpWf#GrxPQ7#Lm+4fn5*e`U}BW-d{ZCrtdAhAdOyWf1*@ z{9D%mj}`fjrrztH>|yygn2yt_ceqVS$*sGu2s!(qk*R57g`qZB_o%gMDmAjK2i47+ zK!tm+^x^4m+njwSJ=XJF3`@G`F&-B2dFf3Q437BHK9WiHd4V#9?9TvnM4{Om*`D!F zHu>_sn=-Pc7W+;S(cq!SL_75ks}zybB}V0Z1+rpgsUy3ECWTzBGWkk|5$V5~TmV7` zo(!Ms>QZ|_hmBPqw0=#KhekQyghms_qVF2e-?!xj*E_m=Bxo<9d-zkZO}kR9AO4Q3 zKb+S~y+$XPh>+Du+Dc1{+b9u_?x+u*tIijI&tEG?AG$Z$LF!=j4j)dhCBOX%Gk!NU zU^>?tgIYb$$flIx=``2>1mT2^cF}o7A*i#05 z;b`B$47a7REwQ>GF2NhBtG@P!VKlJk?*%j+!+g2Dy-CXv9~{`no%jWb^!{Hv$Ra!$ zImLL(Q9T2o{9ONFmakQ<&K583gDK~z$~vSO%P=HY6A^?vb12>d>p?f44ls3q-D)FO+YFeBn+ryw{@?l!~b^*;T|E7PVrlS zw(zGw8?)yk(0ckuAM~`p?WEDF z$BaW9H#hp1VxuF5v9t#~1Z?12;o@2I0ys&f>6ZIN|Li6|H4y$IHpJ>c#Krxbgc0LT zWvj0Xty=4@od8DN*bLSZ=P|qLJEEs}$Hm1JjS99HpM9of&)fb?jmnVhJ@1j>W{Lk# zy~kp~1qFu+;{84hZnXYLZ_p^SdvGy%==O;TwsvwPEVW7TzYyZYRX{~3+7*VQpDBVX zG*r!tUJpuaEt*lIVvsWb{E3dKZxVhd7}qNC_iU9I3*(1`1ap9>WpHD;23t^P6Uy~0 z`DnU7SNJQ`yc>Cb&rT(5u)|`4nuLr*Tv#m=wQ6B(B8^fk1bHIkw-MRD#hqAVsGi;? zcDpGAbIJybPYoMx8mq~J33|-1t-L=((=ptaiRv$H`XzrAoTy$xJQhh_=C|mSa^eJ? zDjRh}N)StjJK_E(&4u#w1BeALx%#_(#Co#YlwRDJ+E#1NHr|-nB^UNt82}?=%or3wh%z*^c&|C~_?zWTR65>>|FbtL z8C0Y!lcge^>k1YeW)k+1f{a0f7zJDgV8PJ3$8GRa&pca?M_QBpiU}sN`Ak56lv>%( z`rnCkYQ%*n`?g!%#9lKh;g+-g8^Wm!SQwn`Ud4qO1kEJ+9%Gx{7 zn%{^IvuHRfsdEgof1Y17TSgMjAL$B+uy08eu)60a^I9v`(%@E!_}|2g81{o;AP17a z_dsuc#IbB`>i0#KdfN;qa9u`CCS5)}UWJ1Qrb_#Y`RP()%a+$I@muycq~CjD?$;6U z<7bgDr|X!~+L23LOkI4mR>N}q!-+(`v+BBY?X6nQGWV67GJ02$zY=G!j3E=S9O025 zEPmPi&CW*5;H}NS1xiz|pI6973kR38Tby-^dvl_3%Yxy)0nhTpMWdpo5PE9I*=P`^ zyCPGk@X}sQZ>vk~T6)x3teN|UL!3{HyD;RAq4oQqTlEnkQ&uO47eT_wG5;swE_|V; zl#xj7BK20`5nmlIhE=a&z1Nl(z5FJZziK~r&qcLBS68Ij2kD0o(y3Ocq4$+W!QBlI zHIic*O*a9xm(5U5Uhkt>q^+)Jh)&JmBeo~W^!09ALZ&|O;xWUg8@?$<Amq;DoUS>|rU92`3I%VFKRcf@#W{hu}hHdtXeRN3d zDF5a70=4LHVY0OdUwnf@xmr4pyoG|m1XCD&fo|%p!H=Vy1n^9YglpXwFwd1wU9Iy4-zp zn6{x% zZ#?cVaiM!^LIKxGC9+x5_Bm1Si#VZO01QevPSaU-+hsET_lx$yUf1(Ql7e+F;r;jP z7<}abqU5;+8u`&R@AupnRI}%MkhuKHi|2e$LdmVg!$_m8%T%NjWdP%z`ckb=maOB( znyYr~7kf6#ITsIIh99xeXwUcONjV+wvd42Zj8jw5-$~CWmKt`q={R%Pr0haM_tFV@ zv!+fKs*-5tn4SsfC!tQQV(_`X9!z8<{KBL?_VhW3K65zQOVPGlcEF_3LdB9syYny> zU$U4htB`B3?}ag6uP;Kb(QeSFSy&-N-E7b;Fd3tx{c>EhPDVF@>?2sya4M1<3E988 zc8}75eANP+b1h9{X18WO@Vtrr#n&>#xZ~e4WF4C zDzzDJN=>?P&!6y7VMbtvh1Xdb^TE|AG`P^Sne4&Wq@{H~bWFRC^)+A54kbLnpH^pa z7wP2*m6O;7&X#Gaei_eU-0DDk9s0>jLwHP;%R*Hg#uyyLe66*a@Ex;`Y&N;r%i z4+ieHQ5;2*bLAeLuSD5a{A?HYY22>WiBvjTY^lJJSgcSfBcsALrbG8f!+E+#<0r)M zksRGSnmAV(0PQZbvp2WXDOrm1xzU6y@cxjbSI0wr(D(7t^lFJRXZRQ9i1JhP)g);Q zjZQZC*DGK9Kd9OO2#bASMRki93<^Q9D8<#2Ne|RoF5c~YhQq}q$&uqo)zz?N%~Ab! zkV-S9Y$mE3cyqD43Lo}$c8AGk;PYp>)0(=(4uzuOaeBG?cnL7uwYJWK@)PGD!?byU zC%W8K_A#Dt+3>4|zGK-{C`VJRfZd2;$_*cupW|c{$CmaBy!YSxS!&tvK6XOXohxVuWd`M z^t-lF7cfq(rc$LwVmzEYchKJ+#l!<4j!cw1o}yJABkp~X7C0IHbA#FWWG*4Qy~b6C zGV%SZGto<{Q8=&$<#q!B5q@GOP*J>pW=cUiviJ)f?b>GSoOxUvrXK zdR`=<>q~E$7#1nN!I9#8Qrtceh075qo1&F}tqXLEd$ZxPfBF5Ub2@eMy=)=Ze|^yR z-?`h8WLG(x7T#{M0jEYxG8~a0)_r75qYr4{cam80C5;bJDm46MAU?*Xdi zvmn7rrH4j%pm+}D0v=gj zXK&Ce3e=j^_vThLii+#DJSZu~Icy*EMW(b8T<+R%jE>|yM#SX7q|%3*2*$n5?m&kF zYrwJhov&G&ZpnBsE2xb_?7XeD=8GUvBu+uX`g>Pky-w0Q8~KgihgHQmzI&F1Sn1Ej z5?nsvjqeGPi#3;fsFrJqmSpjm$FDBb&x@2Z44qu@UV-8kc14aOGZ> zsq*Di82dJO?&sIWOp7*+Duun_aT&RLboAU4>^5i2#6cLjL4Csw-wm#i;Zu(#O{#kzmPbYNM{tc`6AZ^ zip+cHKNq4KD*C=jlrNN$tW|f2MXZA;yaTnDzkC#M_@&=e5DEwvv`cD0o&{p?xWD%j zQA5m@^M}D!a(S?*uIr1WZrHJ_G+V_alU)9|hebt6{=gAl7>QVMos4>#tH3vuV7GPI zRTeK21&p}PnnFQE=*$&$9xwe6Z$N=)Dg-~oyVf%y-&QF4ltv}YO*XL z44R$KAzcL_;j({I=UUKXy$ig*WgBqrzRkSaL6K}6n=+S7q}!XOzuq8^fHqVj7SVg) z>-h{qHDjW6)Xnj#m+7 zaWpEkzVAJp3%EAa@V#qUP`kL6PPmvm%XDKJWQ+YP?T@vFnl7UDa#yP_noT`B8Do6I z)62p~`?Usx#=nLAkb>!xrp?ex7`-@V7wR9->9G*W}53 z81L|IqJ(L^?0e>(dkB$-LqV89s^6#AJSrJ58)dVaRomX#ah4@$b&AXH|0O9ZwS%=L zS*{NB&AWsJ4}>AXB{Nhm*m;fNi{}HZ7hjuI1Sxs%6{T0;YNV7=-q)IpWsICyoI)c) z-jWFLJ-M}clkcf85dYbCiAvkeL+wVwaOtMVW0gYEBu6 z9qtS3F0uS1G>lwLN@>aBt+H^fdxZ)xFXZMh!sp01B}4cYcSn^0v~RXZ3bCd_Of{LS zQ;}`d%V4vhQ*(&|f$*F{yQL3>AQD&iRg?fUTBcSOA1%c9!cHn@n*HgG&GEG@FzT+H$E z5PGdrr6Ci6nb4*a_*5RTPa}v!g0G+I1>RHb7LI-_D1bn|s3K`f-h9c$27z)^IXbmB zK65~LAH=x+hp}M)=z9*&)wIY$d%JxcZ?QtfK5m)!DM@nkMIQ0Fyb~1tE2msNe(A z9Uo=Sxt}qJZqjU4Hq+XT7f!yZxCj3B;OABw9qmuyjYn_6tQpFI@KLa83h|_JJUGo7 zjTX{5GTcPlV{X`%xN`cDXzImn^scMkfYF~j*wt;76{`+2Q8o!gTn=g)?B-v4=Q!i8 z4-#%~W`1B3=}wY+FV*kexL8S7O7XD!D6Yxt5HSmFJ~HXxx@qZ6JzCxV8ZXJQImv4F zMdiAHb7zUPtkd{yoy|C%WK)`8o3@uDba5eFuR*JFn7`OR^xZo`8y&AgP9 zv_K0vO1@`e7KgiM+WtLDG0Gg9hsVUAD> zCzpGdWUi>T8l9=u@nAw*{{2tm$!-tT=(Fi(?dEC2KiuDjZ(Ec^f(-H2S!a9Q6o}`U zz+pwc1R(>1w|r_n)J{ivz0Y5_va&rEXFP!8hhIMh0{&nhhfl;YyR9&Z!5UUFg&4=< zLb6M{LoShzqHd@ERcZ)`@jGEuM^3hNhv|cj?pFHa&&oPHQAz|Tg41_s3yLk(Q^Dj9lGtHhG z3AONoZX?B>)S;+~h#tDmY4NSNM1nQC4Tcp{fFz$7xk$wqiM1rB*b?B(?Q zZEvFhw+(RHqK@R{tIc1<{%8;Y!D@w7{@fgjdx|7%Xz|wOULK)An=opOG%;37!uUH8 zL#G(pVmiq4ymf-SsuhWQ#q*gzcd+-Ri~jo4lZ#qXgHRpp8ouj6 z!RoQ4z1U`6aBMO!1`=s+wppS}qE)q*IXy_eOw^BUHxKI346*s)reRZ)Qe*W~%#GJ^$N;v9RD{emjj{?MPS~coMdcUVOHP=z0j4b|3iRLW(@jW&y%|>rL=8>9yXjPz z!oH6>nG%YnK6l1ny^JYipyZwqsCAE;mI?*`@>p5vT-YEa$0mMn!o62i@!lUr)L4)1 z?)WGGa1G>@p6C;DS}nCnxQ?*sz`99o{p8ApdAe7;S5n`b3WP;agcr8TsLpcPM-^V@ zyYFzzsBe9K<8mD*IhVopT`-<=4jg;24q0`0CiotC`CWy?rVkN#rti;zLRi@}d=dm= z{C5RR-~#R9jgv8BI0CR}sIhZ{8x8-5Tb)kM;Acoea*5*+eM0Bal;{wv-77D}ES^PPSiz^Lw))gJQ6o6*oDXpTs(BS zV04-{IyycmTtJo6$(tF8YBW74sjqKZ-hi0i=^t&t8pYw0lfCEt z+V9n*1>F1D9mt|Q4}%V~EeQWyfdV3=a`bWp#9@yzTs%L)ms$mLtq$dNG^aIT9++l4 z;S?b3dAm5F5=#=2@{a6sS@%3jX$WC9O#zzgLDff>MSgB?x>{Qqkc;Hu&lI39jSMXI zzPjYp4lzwqgSyRi3p&o5_S5jBqo}lB?)7z^9{3<2G&pWbAc0}4ZQ^dX!;oW29;3$EM z0ssl86d`~ZHjuk#28;q5L7&adXfwRK-7+g0Z%{}LXDZOpVz#^}cs{iJ1#gZ`OtsT? zc9Aj+k|lR79l&PA6Aq{V-%j;ManI#W;SVuSA&F;VfHLHkcO9KHZfA(D;~37!Ki753 zxM&ecp|SHzWi~NAKXC*_03NIBeBL)#F9PUQauit-vbZ|=EyI|knd+^M6nOcLit>b^ z8W@HAaC+~jP;b41!oS+Zq=$czERq2;n703Sj|r6rDxjw~f5V_g1Yz9?G!a4SKe163 z`zjhmB)O)kTZMt1P$;eM8-sZ6RGKuSwANTug@DD7k6SHsgR#5T>QZi=lB3k1g(-od zP>p23nmDO#l!;Ey6v=z&y73CMhtzlIS5`fOA=c4@6~529v-qWp{WNd_4m6FwVaJ6# zB(g<(-Dc+Nfy3^L!Fvy1tq~EdIbS$5x)AWHDduEQ8D-}3Gw(~|8C_0?-5$Nm%@b~t zKU(c*m;H4~zv1&9c$eNq8iZ5sQYJ=MS%&+7!2C@O>CXU!U_ke2Ddg#1O327iLdi|y z&>temcg-^O&Vd-bl7VBbVqWYY3zcyNQxQxi{5_{ef9@}~ge?S~5SAkXDK8B9A4TL4 z{hTOe@fVPs;P|m|8~CNuXi#laoK8!3faQ*D%vaU~?6)&`A4m_Y)jCmEqH8jo9m>%~ ziUe5PgXkl4=}5z~Go7AP;)}FunC4#LKrvG}Hpir+ebaU%ZAa&|Z@1lkH*YAsm4mSY zja_yVYgNU(AuSat>-vvaUu@332cI0+a3CIJm66nV>|rTKzZ&Wr1G?o+6X(7&h=Dfw|D6%%lKAOz%SruSHr4$)ys?s_!Vk@#1cY3uv)KU`cVIsbnQ)_9X(;zc4Qk(IjV=+VGz~V)FNq`GF=<(_5K3+6#f=b6FDj8!fduOBegn- zf*-{_bHQx<4XIB!6nU7|0=N}Amx?uWcCbVVb9_&l>lw1P`P$_M!-@;3e?djee`5&1 z#a0_M(<8z?zYt4hrkcM=LkeVBPdsO^J5YIOqc@C)0aq80usw*!@1P>Q`ery-_V`zxVBI0Rm=+9L&P7F1`u6-WEKOJFerB}hiNIE; z>}~lPfnS)JgFZ;#6c{bte~OLTB`KQJ$hjnuvMlstIm+dD&W>T(y5{hDiKl`hZ!Wr9 zdS?5eF*=_lo#isi_@xe~LzgBh2^n|8U)qznc@K;={_S^_nzcj6&1{E?B>#s%S+C zx5&05^em z*;TZ4t9I0`cA<@m{_1292f@1?BZs(ox-warny1ue?v}RG9S?n*Kl~B`;Kov&>7S?D z!)A#~Fdi9qEO@(P&@VZV8MEVvKc(ZINOFhx{bpZPlX#J2>1=XzhMxS0&IJ1}2|wEC z{;NX7^4dMbLS`X;=dykb(8DwNKm>dR$clRk&ZnykGOhmtI2aLue@bSZKYX@A%<644 z`}y9C|D6UlntMIl>h8aB2(i3SRBET0Nk66_IY=~S8%wb*>n^)UJTy)-fBzG*uq5CY z&=0Y6WNc5W(M%{Ci}Z{#)M7N+CiY*g{y)eNf*ew6E=tQQT*MkTU|wNg$oe7&W1Y+N zJ)}pb6ibS#RCJQB$YT!Yl#xU);ojSy==IA5g4DoUdBTB8WB*q}Zf z9)d7N@i#u!;jGqaK00Mc<1N`!{|}I&OX7oW_;!zmufGQaoUbTF0u z59VN#A6$H8rLkLk0XtS-*WoPV{8eA=Y?MCfQK`e?Lp3 zm@HD6!=*_u;y}m_BPFzahOqS;LDxfx=wHblPsAHL>oozy~#eAfWz<3hI{nn0Bi{lKPv8J~(mD27{K$?u3T>J2c_r zi7Mq|`a%aUIr4w?_OI(#JRh#jx)H+^N zWLNE~@V&1DCBi>hU0#ZTEc$=_Xc4+ZxADX=iu|scRtlj&!`FE#$;qIJOf*-s`BD>< zh9X+(sKThDG+chYLhmaQv>Owh>=2AFd~P^sJd;-tAD_;xGmDdR0m#&SDL!3s{-a(} z`p2$pu`~(aoUULUKN z=EPjkmH9b<8{J;5m9Bx^W`!!vtVg&qvCTENk4`PW{?6J|gDnA)sO<~tR6aOWoqVSg zJazKMb4oPzQg=d$@$Fk+`S3&eaGPKyE0v3x)VXuj?YRS3Ye8m-G19M5S;l zUD+#bhcb~>r`90qEr;D%bM+QbZi9bL8v1TyD7lFk3bhWEmc=aHQRTqVjH&V43xPxP z58-fH1);Bs7+KG#a1p=IsMlo26U`#%Q@qui;_PB8x!hmeLOLiJ{>+Mtl-dcisW57PHKtKY%qN$8C{-SCHD!xYq?G;h zr+cFH^Tp*BMXOe6xl^H}pV^-Y)!!7_VDBTIsuu+P2snOAstkev8f5)6_@v*bzoDO0EaJ~u zrqO68(D&&WY~oYjuhSJ$)AQfzvc4A`WVA5~$4ic1%MpiGnx(cE>*8+~1A)V$%IXyr z-wt57Ye8WVYJyq$1*CgcPB`H|BogE6)qjPY*{gpdw@EBu(T)AhR=^tIpevhPYB;#M zo%(Id@@S)?)ls(`J&jkBBSlWU^DHv3)X$FF`#6zhoN%$$qNwe1mF3PXX9Z)>hib$3 zEnGHK>>jW)_{c*+ivbk?sJZelQnxW%5YzFt$o11TvD(Vy-(3-O9dEW+HRG+QvE(~o9tK2?c_IrXjvBFdq z{dql&o{OVAmRg(}GL=zC$6PdT!RqZ#*d02btb4o@)JKk=GOmhfrrw51>&;RLGHSOv0)~LkC?jEg%(AqP~`rQ9L;)#I!EO< z*~F{V`0H(`2>)9n1Ik;Tr9f$np40g&?H|$ItAG&Nf8Dp4OOZl&dOh8aGbB6n5h(zPqcH&1x4Lcq-x z@zx!dQgp4XD&-#l4IN;64Q%ot5*e){4K?l&CptVUdVishX=9S+%V3r&aW;wV7I2v* z5`8wEmmbp1_3L1i{>gacQx)lX;=CuLes)uz$(c+nwLi`#!Jq~>USuZDCQq<;ncK)@ zL_N_nL&+t~>lyc!VnS8@O5m>N*N)Sm;I^pv^rwNvWTYcGWjK4;nnBHF!R+XdHnq36 z)%Wo|26J_`Ejj`_%NR6Qa-3C1#Iq~dj1$bC6gCCp_>W?H29xm!6+5hfq ze{2@veMt@Cu%zCSNtc=xh9r}PZ>$|w)|OSJ;JZF>9byV)9~Vjfa-vW!D@Cqy?D?6N z%H-{9|6XHy5b=8meY{e6P^Rj_RF-nNjxa*p?eHtIW`~`BquGKE|0RoDj|zi&;ZCjZ z^S;cLbZ6^c`M~YolIQbq$671uS);veNA>-h=hsPe z`hbBMN7;F}J$o*{TwbEM0tRC>Z)+A7x zGi=_?sOlav^`V{Ctvvl%Ac~CRt~sRf{_Yw(loRbrXbM4@D2}`UZn=n}>s9QY@hVK{ zBd}jaWSUx1pWc{#4&T7fa#Go*B91~ZjkpO7HQ1r5o0n6%^ET+saS^S_mNP>sXAyn) z#n@_eq<634euE_=O#@b#KnD84y`MMGbEj8Tck1bj6!JUCNh15UFys_hb8V) z(9?Z-6T?L{A~w60E9|LVf0AUW7U^X$0>VIV&xPLc5L(U2UPnoG61ws5cYx)*EphO# z&+uVt%*MmR&)^4LO`ba~C41xVyv1_iAjru6@aXV3ZXyC=MxI68s2Q%p``|LzsNi2; zZhs40Krhz=-{vQ-0^2=5`CLc2KSg2lU&%ZkHlYD!{3ehH)wUb9%XpdY0XXA#U6bO3 zvnZ7B z`P#r(BzXPhNebaLz2?ZVg4m`CU74r?1_F`c&dzy^^5r(>rlX>!EgvYnB}I#B@-Kfj zy?Mc^u+#$vZ;pI#zvU~aM#}!tJxTdCSCSo@0Xku{^|@^FIR;pssPqq#+}TAHQwv`A z(biZnF1IowCka0jEDR;`cgT~3)1rb-ufCZMIMK@!8%(`IzBX3Om!I9@k}%rd2XU#I z%&WUsDJaC>zP1`(o8YirYEr8MD_1ufS{sk1Mfo1=f1PeLXga&66>?(6ep0R&Zc9T3 z53R;mr1YUj(k$fV8J32gtLv5*R{~!Xr}TR0KyG@zoWN{otf+>3&}Qt!#PZGh%&}idzBhsmP{s zDZd#t(HWlsI;#PiAtxFm>_4xTU=+TN$ZS~d6w5BGwOx2)#IYapsPi5Mm5ilqwN~b$ z)A=`6wh>)qJ@g2_?)}nfzfHw(vTf}gWUCkE-3-*O0{XC7uBhkrZXuT?>a(cYj|BI7^YhK+j6>#YJzqr;w*sC&YM zf>Y$99{^m4U}{xbI#K7L0Oi$INtAC3A5~0+S)}^**aCkG-uZM2-YqXQWJJ@s7&`-v zz{y+FK{f!{oHd<9QIw*tWGXLRgGn(%a)P+Xb`M$pP7;Iqyt_*ON~Q1^mHYeMgJ0%G zvhyG7ff_AJ%Hz2!jdKcXhWI5#pLrx79yTwx3wf?u*O(V>5K&n%Zqeaam6D%^OO+i= zcja$~t~@WLZ&NLvT{{kIqV!q$P?YXg4^kdt*oaI)BffjvqCf<&)mPJTvQIn+G05JR z0av+rf@xQnPF}$@$Z|_pn$~3kIJTraDL;#M+?x zBsxu%hW^NJX;t^zod?53<#-Ul@NO7HPYD|<-#CP9O(HinT}7=0TfVm+Z(01hM20f6 z<-+3h`M6Y z=^AET4;QIt8e_#dn0Yw;u+UL-dCme4>u?F-c9TJDTD=lPF-iMafSGK7z9FAd<~Z#o zI`vG)tC)`GlZ54*Gj_I=A;9%4pC~g*LEAWR?Lr=8e5l?s@=;u$y&1W$&GNkfHbS#cm{!`SMnv^`{X8xMy86Y zcE+VQ7|FreJ)-f+{4-3;k8lpPK^xT}^xJ1>zPmdx4{d=_ZTH@&@AQP3Hyt0(m~xyn zsW;#*V$Rls?j>}ZMS$z+&QUliPStnH;$ zZ9H~KkEW0*`Q4KKVjPeCDX`(3NlSp`4SiVfj_|?_UdqOWPN-4~cbjvpIFJW*L%Y=QVz;{idMp{Wa!_e-7!PYrS0~GPuHKO?wVo ziB&SHn+2NjB^5Mli8pOE@^pK3R2pZ(Qo3Mfx8sVGO%}E=v4KY)gW@Zif|Kxb)_heh zA_XhStk<@Tc{CH&wusq@8%Z<}w$mXhT~-da&Fn!o=?B3zO9#HoLg}SCv8Tl2^HGV4Tsb`rtAb zk+)mTT_u^&!5$0*R+>vu=BJ)o&cVTCY z-r1H;FBZWND%Y1n-!Ea0=nWrl`&%>hqHt5N`xzIm&p+ui@dNGhNWzJtos&EI=AAlv zkkXqbwZSYaO8T)Ef=aqKBJpUIE#{rr+1rvZA3a+sy|VZd?+PMdv)}T#dx?&Zju8qr zkczgSmFI^g-SAfd3u#~Uolw}cz3$2;TA7{D{8L##b4-`>O#l#vB`_Dc zgXMA!in|o|5S3~D?kFhP_rrafoqJ)*YIr1>+2jK@A+wX=_c1Rlj_rCxR7!1gj zj`!raq*53eQ<3Cj9A)te8eJD;sq@w=c1}2Ya$e$K&JuaKo4FG*n461~Ku}>_{){oP zp>s;psmzXj7%>&FH8$=_55BtZ*uyev^*V4*Yr3n9wpAUOa%R|y+*w3GKZpwxf>qeF3eR^? zkwG{cS#~tx>bfT`B>-MQ%m6S8)S!#O;C2pV#IE1vCcXvG#D zhGa*|GYJ0v|U;=N!NFK-t#}H zNutH_V+)iBlXOw!s&8=VsHj!(0>Jas$Oc@$sA?oglC=824W#F_Sas4COs7hi$@JOp z3;34&E_Z3wRsIrcU+`S--s;o&E1s(GI>E~x>QkISk+lO71v#qzqhZC#M^5Wu!`0nw;VZFzpV|#TxdKvxpp1pZ;l ze$}Lz00~;0Ge9#-BbvVjrn}p(FmMxVQR%vg0;B|GIXBu%1}*xlg=-0+*kPqiSoJAZ zl0!|^xnGRNx1<&C>P~6zs9eu&MuPjZVCy4*PW$xz;l%I$E%NS7)0B3%;*)+qOwl>z zy7Iaa&Q(ijbB@3G+P!g*--givz*6_T+q_ip^&*&tkT@Pr+(RJ@c7}WuE-_K$Y2y?1 z5b80hL-3$Lqn}!Spwv%9Tb6b5qd7}l*CJZI$q~*zf6myl%4s*W2ng4yj(!l+_q|6T zco?*~eV95muu~=ol>|=k9zAJ5WO# zou!n|xc{jn#q8rt7JCl$y74y0^!enm>h_ zHYfA_*D9_30bMwdGtJ=;T|Uc9Ryj4+>Tsz}j*d(6*qzmLS47E^KXk?^50O2Tj-|Cq zmqVU|oXYYreL~gafe2Edj{ucQ5I4QZL^3nWgc) z48F=*M~1eo%t>yozbjMd=DxfR-8tr|KmA2ZQUFK=%HGmvDfq^bvV9D@V4{(#k+_K90`eGkkTFyrGX{A%0hmzxQ9OK1Wh zU|r8$J03rK-jAB1eqMMt>n$C(&#vtd&3SvZEEOb$FZ;5FL9dA~D+2uCsf4S}q8{GQlK!XT^^TRu9AR@&@E*Vr^ zWCuh5u_OX{os1`I^`Wc`3*4(ZS|Exnk{g)8>Rz4L{q#+zzKS5r4|vRK(h5t+H26A! z1mv9rMSEW%e&aO}OJLuatKX?4f-9q0QTM6HVuoOpx! zq3c*bd%Zl{YF-xA=Pa`TWSGi?B8(6(Zp|;-(1y@NELavg>NL+efDe-XG`c%KMnw{1 z?O~{X`nE)X5t6AT`ivr-hThRDNVi)NZE#sHyLORQA-`D2tW_yexLY=gH{yHcCG}i_ z&s#RQRI%tS)J;iKzsD5>OUC8?v;0ezRxc)3eq1sWDSabRDHD%c!s4*6Fy zP4Z8mN`Bv)Cye#yZ?PWNPLQDB;Ffdby{EUGdS>0ae6hG#+7!5qsx#*Q}N-l|dw~n*cuFceI z#K<01CYd}9VvpDJ*BrLVRK~xl*NHG%T~2#(7H%{rs@8=xQ#j{_3WJJbvzQBQcQvk>9`Q3Q`J9jM99GHBt&#v~X!)p{XE zVZfqeseQyv?H{ejhzPu1L)3?8cUFr=(sW?YcI?6G&9VGJf#qp<;nuvzCYl$!~WHi2L%Xy2FYyj^}?bff<_XGNt1h`QKkHQA(BUVpgvgr zm?IW&VvN+1#>2RmWLuHs-&q{uB>;UfBj}4&6uAJM=CYA(!SG+$dwbc+ZC^$ z8jkGpXbSv?Rsn@M+z4YJCcWU4G@R$;)fltMaDXtRk-GlzAsTs5K1-|q15k( z@T2_uZg~uFi(#N9ulsWcCcTt$lOws6a;b>?e9YcNB?y-p&r0`Q^Fr(u#Xqco8gy_; zdw)cV<*r_9i#X>;93)FP7|B;bg#dHOe7NG@-V90+>VZXS3&fcuqYvFO4sM)e(0Gl- zLmW3w{D)j%8umZMn^J2c zVh_uDdN3e((0(rBFn4D;jc7^x%S~{`3JgF@Rh_4c0+0!zv(Xdd)LJZ$bo9 zoWQTvkBAleazmLf|4uq*fxsR_+^bnh;28p_XoJ#9b9nmUNRql}R`$R1B@jZ1e#X7J zC-(HrQ=^{iHe7bf#N!)|+3320gyN-F6Nf=A{)#zz=Rrf{D6h8Vzx)uYcwT67Moow+ zMEQBKdyo>g9&I1)`zc)p22&IsbLx9*tC@~g4h*g0Vm=pMGw9&j;#lOW0L2HRZWX=AUAAoTc(f`BjkKMvxNPc*sL{yQr#=|7Ai7gFEobn6O1oJ zNlo6}4`)`&EP_$nYlI(HeIMEi8toYjnqsh9HF|Q>@jm*YO6O?kvXxlN_DfpHz2`zi4h8 zkNwzA3DU@@-5^=h12OZ7M5Bb9$XxpUg7JN1&of!lkTGDCvA0C^IbbAtRIbD9u}z<4YM_1Z0&l5`~Fwm_{;HuH|CC5u@vo&1O7eG%AA zBioTgYWW%C4o34_-zCW}?yA za&R7aE39O-y)!?r>E{&z(iTWb)NtRw3koPlXc&xJ?oLH%{PlCNWuT;RGfO%yV|FfQ zJG17^@%Pgpo?HwvpAA{)xTv>I+p_4Ndwg%!$~*ag<%F?qcc9a$i)QWjna`R^ELE5d zJK_TaX64gnzbEA1DqCWL33`n?D0*!9sR`br#vzKKU4#t5)yK46*7cYe4;GvL*4-Ci z$`^sw`#L?3v^o&|+Um<-hbGF_zy}g`D-n?z+eL~*M_D;5-F0n}Fh-Eu@ek_mm*;lu zH>#3ezkeAmZ40*ezxdr9H?J4?J>Ac?IGJQ{JLC}aI*T!NKRQQ7M8xCJs}C2+eJb#M zxK{4)aB9wYe7adrOirfCe(UablFRE-lqKM;Ue&UN$m@IG@OXb%t=wp>=8I~P*YGNK zz0I}!!{LJ5M_kwSd1h+r_ijgv7DvG&FGb-oZ^R1}h^R3C9kSCG=LaK&=ubO-o&zDdTX!7oI zZ@02}4Kt!xxlnp!vp?MI*Yua!HdmWgz(tdapMT|ji);qld!Wl`7K`<|`cIcia%#pDT_lMg41z=oun3jfiW5$8y*>O^U&Ms#jZd#eFm} zW_)qRbzCE5qDQ14?j;s`<>B9tAK{S8h};L8H^9dlAb@g#hH#3A*d~dPI!pb2H0`T; zPBXb^n1^Y=pnzD=TcE$QRccz6b2C~VPP+}FYlH;dS6$QC+kvJa;V!Z<&sq9kFIimd z<@)o*iN0FP01OhOuMXx5-Ruz6@pxAL*F`drUj$+ai_}5JYd0twI4B4TI5)k0gEuQu zVyGM0J#;%dx9Z2fTI)*|0vRZpGLuR?a{@9%@UVY=PutwBlxWG~h;0p84S z-i&5Euez_#>vhNu)EM=fUjCf$av6*!sI!iJ+o9F(9?yc486R@- zLp9)+0l{j*@bKrSj~Bxq-~M+~f|h|;>cG^`3*8ERcp7D3;`l|5%o17qB=9=tf=i@N zFl<2OK6>yIEB(SYh6VTGxY3dT&5(ZT2ZwT2SfnW0%{Jc$x4@DNe$P6ehvViSbF3DV z!~`}3WLL8?%==Yl=$t8U)MoXD(Z!n^GdXRfBQdFed!!OMbSR}+Z4E>+K_8S?cg>!Y z@O_xJAyz4n#IU#{_^-+5@G>Y!y=J4Xg$SIxnl{F_w(Wbhb0fmLp$%x!=|coKL3(kc zi>UZl>ecEL>=RtJi=W|diF$)-U*qRrOatm-Y#2D? zctQZ!2|>X6?FN{xjDKM|bYJt7U>OYiFLyG&84PMPtkp;K&|z7is%H;r9h;kL*F1{x zW{0e0hBvdcnHn)fsj+y-128YcGdnREvQnw(N|+*^e|GAde^2@DxW4?AZg>FkK2ru6(|!p8TD6y_%k z=j$~vGY1uG6-@!MLrWYpM7dU166b9@;=@t>6kjL#S+dY)L*$5kO!J$*#j((g7M7v` ze7Mg1c7hI?8VNGr-$7Lt5ksAIQmj}|Sd}|BT>fD&5;4e*7E@@ z=aUs)l2E9Je2F+*567yG3+X@!I29I?XypIK7m!noKbsK~ikSH4wvTs&i)e8nzF83& zG>geYT}`NN;X-FWuWHDm8u001g5BYwsxNt!_qJZnY8ou5FmY3(=rhjCjM@y_H&^M@ z=@o?#x;Xm3^`m1KMJ-Ofd#Px5@bp6a$UE7l-}a$&JV#)eAk+jN5RWyphSr`>rh|CG z&sQL*r)sR*>NP0U$QK+7wI&jbn$xZ*?4N`ydJc_A(j8`<|9jw#e?SPy0tO1^oZL8B zb(GYnH72t&=k%o}i2mcgx|x`Smj!|gZG6Smgp1L9ODc}dd(sxlDYeygL{W&L;#)w# zu@+sW*Ur}-BFvzP5>#l={X)YclvW*1=BL>m{xx$_g@>0{OW)`GJ>W?Ze7lL$tBF0% z0T&o}{zmf*Q#u_(#5|@&L*EmY{z)t728}euWGHsTWlErUeOr#q_~POe2EM#7?~ zKjVa)(-f*AbXw(i#tFJM*T%kzrIm`uB*RM+z_pnSRxdkr>-{kj$kMAB7#Oe&gcd&k zie~^e{~3he6Ghocu*MUI_fCXE2wT|H&=wJd6l>7p_~k?}jDNDkCam`!SpSoV>|1&> zjuqZL0S>yAI?eL-t-H8S#!^Qi@ZeJ|;VvFHxT%@X!oi?Z^FSkFl)odz0TXNm*c~E* zqO=?dD*Hfs!?MIh(vuNiY|;oE*Cjhu`c`dq(ecyYkMr3%nh%JZ$4*F+1Yh7^hCR@r z1l4);D!v~7ZN_cj5FEak4je~t8LmxM?M%FkKTHIn2gSEMoU|7L;%x02$P=*5Hnh}` zAwj{;7&QWGqjq;aEPG6b6We09-7;4;GR(bE`o8Tz1cp4uT#b<^$<+Vap8Vlp#|cRy z;p#G#Te7B2MPS#XKqV>F2JuffA_ecseP?0s0^)b`HS22bZ{3C@EA}`lMHRxGgG49! z`R~g#P!EiMnr{9%BhhJ0vXVo=_4T_r&&hG~8eIGub1@!`tukiukT^4zEbqMxgf&qx z^pGl;-@xe=^2die>rXOnEY9`Qexp%!^n3cVjJB9q2xsKRZURfkydWK&R2Ujr)l?)8 znCu(OX^Y`hx zLH9AK=Z`U$-@laZPTEgvWY8AF;lUKJcYs650J=Gf=nAmAf9Q}O|EJ@FgsRXPeo7NK zL@lBICNz;@NlGimV-~@N$gvQv!3LKmu0~cEGE`>?l#^DLr-`q*$SC467bAuCUTFGc zczSnmlIVZ4G(RrWYi}Zc=eN>Iw1(N?0t<}72o`1+v7l5&9lkj&m|v(%%?<`6p=@91 z@qkimInycb<~0oFp?}UPyi2i~E8_i{JYsUX*2x#)^u}Z`dZrKL&<@DN3vvjM>vN0@ z-_hXoU=N|Q{XhGIKa!LVQOFJ`s=71+#&>@jpB-lZSg-qNuTRB>eemm1JtBT~nzRWw zF+A(0J)-IMQZMVZ@XJD-(YwLvXtkixq$OCq1G9&lx@5lf+S~$->a+P zYqsUC){yn;xE$6hVA0m*g6s{MJI;b2wjG@5C>4&IeRXcf+Q%5Zwx++T%s4+t^dm8R z;<76nYVJ8Sp?Sr!9}l-}z~Vu=AH4_vuu0O#1$Qi(Ww_z1tDBWWcN7Ru8vn=Y3PlXN zgBuB#A)d`_G`-@lfATOTh()2K7&iOsF%n-6C8|xD*}|Y55mqc|Dk)=TnO*KAUJoLstom7&dUi#rE+W?+IF>2<=%OVu*dKKM+MGpT%`5I0mD;-ezF;akd~heFE1v}Bfc4e- z0WT{wv?swA!;8kQ{WTBCioE_eOyjKAjl6gl*F*Hi`a=8i6_C^TU!-B&D<((M#|Li2 zD}Mn402>np@q22ZJKR*^Pkq#~C=ZAIK5$@$@Qw3gM-M^ud7L&FMCgVasl*<_n3dX# z?1BGpuqKZ=>_Up$Bj33%Bdo!+O+9i18=yIIglwF_2ovWnDijkH@A^sXq+@16Ui{xk za)%n4e2#itH@PAQVLU7RkeI5*wD4e}q>Y_x7m3p4?9JJ?ztK86HfXvtN*ucPy`j?& zu~#v?i-Ijo$TFgTam1xRLX?M$%jhmJgZ`$ZQgv!|^2)z<;PGP!iZweINW_Wr{X{2+ z3)pl$c%ZPIE0ZsOF&0Pw01`rjleAz1dLol3h?>jr#GN0dUs6B!UTIlV>6KZ zBe-b6;ugjjSZTjYQ;VMeR~9o21~9^C#cftC2}7wLw<&|z3|jCRynmHjLch>I8zN-e zq;N}HgJgn#c;yx% z7-tglDVE(!p>B>)Q{5e)7qb2$Rk}c%TP`-#`Hf+%3*4A;LT1x_a3 z?LtA%bWh>Qn)=kKGxCmjzedw_Qcw8Xs7Fe4$6n<&52%;PaaAfq>KdocwKvmE8Q8;L zZxoG<^BNZ>S+*$ijkA}L|Gg`K2Mp4!L1#cPjR?pfXGl}9@_ByrZ1%{@%cGh>g|moCf_(hU4Tf)PbK|*$18;Y$e28fO~q?C3Jpiz;$?GE|AkRs{wT+W zB1`KM13deEO}c`q=~>ww{uzevp|hwNu&cH0=`Uy1038#>{F}X|%))X(*lpfQr?voA z*8fyTC@LF04Bur}I9RCW1o)=A_^AE!=sE@jvJ`L;_qBnohassZ1M4O;6lA zc$Ka6f4VR}fE*x*OFCw=gR)>w=ro;wLZ4Oq9hB%RK%WFX-0wWk67-6o$((dARQ!WQ znFatO0q*m8{3{GeIUKDfZK^lY1#VZb%tmeh&w#=DgRp<#6s=@By=oE7(3x+rz7(awcN5gGz_7x@yN(GJVM1Sz>E0$cbo-g z(V{B{nN6-=?xcS5k}3SSt2g|_>7H}6*g8fXOGGXNtS!h!a=`uss=|%>$6cLQ1o8_w z5=Zxx2f>o!x~rEO!*)(-@VO5$Y1Rl`pRS+Q0cM=f@xkzDZ39c(Zl`OE0AkuC@v!m? z08FNUxr^Xj2FPZiB4KC8v_7MK;U~(C9N|utS1s4Sje?>?2VfIu*c`x|a#W_hDfUF) z?G#Zm9pEBCD|wWJKX=6Q(+&rTKS6K?09} zDgfeB{%FOeuKvxGGa4~jFK`yG|I`g%(e6Mb*2PYef^@gvQ-SmDC^TTAJq!d3rprxs zn0R=_)dOh;esrOTIMO$2e;~2RA+L?|?IE+FSQ2gYjN3nUTfpIZqR52=1B0AWA~qQ~ zW(x!ML$uB7et?c=7+$>+ONyUz_H(SHuI;c!IL?0qeBg&+LTF(|%_FtJ9xny+)o>6suk%iXY_6c*P!@lw`G_*yRMh-r z?mOl`u+c^q5G1Aw`rb=!55^QK<%=(vej#$}+I)V;^+ksu^`A9Y5&-=}LJR>z*SX^{ zGW49mwse#HZ`f_$4g5QQ|C$la@x9hM79ikp{Jg|Cmd2d+C)x+X@uKY?4OWx_-q*>0 zaF43aYi$y4qdpKLKg8aU-C{DCS|$}R#xm#+LutGj91ytO2zFj|{VoM`uPb(2_!phb zdB3MC4J!cj`n*hl9AvT5;`9fRyxT9%{czK`*6FQ-hR|8#X=JJrYk<%hHH7)kc65ya zM(9n%;en{Lyds4;Dh5D2A}(9U95}t2jnF_tO8|DqX4cm|4dw=sCf}@iD*({~be?1a zg_i-~%=vir-GI$>7#)u}ie2R$41WB}Hx-4E$Ga+0iewn|GF3VP4$Ju82lFz0{lQ+~ z#2Z4QUH}uf1{|kn8Ni?D^n|{fknbi26_NI zn3cZ!YbKw~d>p?MB@P*RwPiG!F2DcRiCJGn&$-=l)BNh#_0dxPoaqjkIjPNBN2}rE z$G0{!d7)lI#>wNK_Pmv$+=t-bXJH1{S$F2YMzMx}pP&i;cLHos#nbaMpwrjyl&ocRik!jH&pzm?XRqXP__dIz_5#0P_Z%5oOnv-T zLZMt@_&VkBK=_Dj1geo3A zV&eq(LLYwdwP`Z<4%dQmOUqcjxn^fyou8jq>pnRyGZ3IFFDEwy<3oo9{J(EPxRmHO zgt!Xonu-^aAti>w#;yJuE^uOY{95bVhd?_FOsztP^{&a>9bm$^Yoj}$ zii1$TrPB%_QPDGHcct zvfV~u(`{vKI(>Zkl^>T#Vgf(pEqI&GfAvjeQkNk;GL(u}KEhNIyc0UbKE;nUPIKEP zWQvG`7k(?ms(Rvb%kkIL`@z@P?6|F(UrRLO)@F)^)3p#;{VmdK7uMKZI(J={}w_tNq zFet@aB1{T|MPkJdzE__v==EkiS9d=8!Ly!<%(ZjicVtc2nBlg>J~C){vRFUcr@eBS4T5$9J&1QX7~ z$3a>lLh_zX+aGH@$Z#Z)jAGdnD{l7?*_j^|x$IY7ueP~fj!XhZu{Kpse$0XeXIo#R z^u(AcqHAMizJA2%zl$@6k?`(=P};7$E!$0Yj6W=F96BFXHj~QD)ViQ{3D;v$)^Q?X z)Gn6lUY8(b;!x5rZR-!p&_f3KT@JbJ<IoknIj!eD}QD|O=y@tvACXXAz6K{Gis z#Mh1kk}k&tF$qLQ^TUoH=e~Lp_mI%`EDY07X9(eZnVJbZLkP0GlnN#leOACeZo#hP zfQ@48PL^$o`)q@vi*4_)t*cHY>wjj?pGjnj3(YF0S*B6`W-PUuXRB#@JyEIPX9Tl7 zZ9!~Lh*;ljAMuF_{AldI!`l!XAS8>0JKlY!LBRUvuI$uml`reEvs*^n^VkEIa)XoM zr(^Edp5m;u!O^2h~QU+5TUd|0&uG6kRiLu{vV!dU;sg zV3)9}ZGO!9e;yeIO!I3@F>BOqu|bcBH$NT8V2Ne^f2D*4V5C}>Xlnn204-pg@TYcp zHJPs5Y`=`r__-A+bu>qy?aTsub1@LcpXP0y`?_BSr+Y0^d;Z}`0pzXQNvbOmSFs}p zo#)h=FOY%>Ph>trLz)l8ExDsf05xld_2Xt^09m;h09ai`{yyN@}(4 z;WfAI3Wd#r9Wt3oFrO0B9SXk8*15KO>p!`q zQ#_VJwN#ZFD% zHLu3Xj1 zr%_ap%⪚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 G`~LvK55mI$ literal 0 HcmV?d00001 From dfe76872acc4bfe79e251c8af71d408631724f16 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 11:01:56 +0800 Subject: [PATCH 112/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20Starter=20=E7=9A=84=20properties=20=E7=9A=84?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 18 ------------------ .../WorkflowEngineStarterProperties.java | 2 +- .../resources/META-INF/application.yaml.demo | 0 .../resources/META-INF/application.yml.demo | 17 +++++++++++++++++ 4 files changed, 18 insertions(+), 19 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yaml.demo create mode 100644 workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo diff --git a/workflow-engine-server/src/main/resources/application.yml b/workflow-engine-server/src/main/resources/application.yml index 10f029079..03eed9860 100644 --- a/workflow-engine-server/src/main/resources/application.yml +++ b/workflow-engine-server/src/main/resources/application.yml @@ -2,21 +2,3 @@ arthas: app-name: ${spring.application.name} agent-id: ${ARTHAS_AGENT_ID:${spring.profiles.active}-${spring.application.name}} tunnel-server: ${ARTHAS_TUNNEL_SERVER:ws://localhost:7777/ws} - -workflow: - engine: - starter: - invoke-mode: async # 调用 workflowCoreService 中方法的方式,可选值:sync、async - join-container-group: false # 本地开发机启动时,是否将 MQ 消费者加入到集群中,默认不加入,并默认生成 GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_debugging_consumer 的消费者组,该参数只对非容器环境生效 - manageable: false # 是否可管理,默认 false, 开启后 Spring 容器中将多一个 WorkflowManageService 的 Bean,可调用受限访问接口 - broadcast: # 关于 Starter 中监听引擎广播的事件相关配置 - enable-filter-application-name: true - filter-application-names: - - 'workflow-engine' - enable-filter-definition-key: false - filter-process-definition-keys: - - '' - fail-handle-type: fail_back - num-of-retries: - wait-increase-factor: - wait-time-in-ms: diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index a9b045a16..4b8394d93 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -11,7 +11,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; /** * Workflow Engine Starter Properties *

- * 全量参数参考:META-INF/application.yaml.demo + * 全量参数参考:META-INF/application.yml.demo * * @author wangli * @since 2024/5/21 15:24 diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yaml.demo b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yaml.demo deleted file mode 100644 index e69de29bb..000000000 diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo new file mode 100644 index 000000000..a4844cd24 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo @@ -0,0 +1,17 @@ +workflow: + engine: + starter: + invoke-mode: async # 调用 workflowCoreService 中方法的方式,可选值:sync、async + join-container-group: false # 本地开发机启动时,是否将 MQ 消费者加入到集群中,默认不加入,并默认生成 GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_debugging_consumer 的消费者组,该参数只对非容器环境生效 + manageable: false # 是否可管理,默认 false, 开启后 Spring 容器中将多一个 WorkflowManageService 的 Bean,可调用受限访问接口 + broadcast: # 关于 Starter 中监听引擎广播的事件相关配置 + enable-filter-application-name: false # 过滤广播事件,只接收来自指定应用名的创建的流程的广播事件,默认 false,不进行过滤。如果为 true,则将配合 filter-application-names 参数进行广播事件的过滤。该过滤功能的前提是使用了 1.3.3 及以上版本的 workflow-engine-api.jar + filter-application-names: # 配合 enable-filter-application-name 属性,当它为 true 时,该参数生效。设置的值为需要消费的 MQ 事件 + - 'workflow-engine' + enable-filter-definition-key: false # 过滤广播事件,只接收指定流程定义的创建的广播事件,默认 false,不进行过滤。如果为 true,则将配合 filter-process-definition-keys 参数进行广播事件的过滤。 + filter-process-definition-keys: # 配合 enable-filter-definition-key 属性,当它为 true 时,该参数生效。设置的值为需要消费的 MQ 事件 + - '1' + fail-handle-type: fail_over # 广播事件失败时,如何处理。可选值:fail_over(会按下面三个属性进行重试)、fail_fast(直接打印异常,跳过该消息的消费) + num-of-retries: # 当 fail-handle-type 为 fail_over 时,广播事件失败时,重试次数 + wait-increase-factor: # 当 fail-handle-type 为 fail_over 时,广播事件失败时,重试间隔时间增长因子 + wait-time-in-ms: # 当 fail-handle-type 为 fail_over 时,广播事件失败时,重试间隔时间 From 99cec324714285c4bda3e0df99b293541a02a7e5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 11:09:55 +0800 Subject: [PATCH 113/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20Starter=20=E7=9A=84=20properties=20=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/BroadcastListenerConfigurationProperties.java | 2 +- .../src/main/resources/META-INF/application.yml.demo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java index 36c17338e..5ae6662da 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java @@ -42,7 +42,7 @@ public class BroadcastListenerConfigurationProperties { * *

*/ - private Boolean enableFilterDefinitionKey = true; + private Boolean enableFilterDefinitionKey = false; /** * 过滤出 MQ 事件中包含这些业务 ID 的事件 diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo index a4844cd24..af6c7214e 100644 --- a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo @@ -5,7 +5,7 @@ workflow: join-container-group: false # 本地开发机启动时,是否将 MQ 消费者加入到集群中,默认不加入,并默认生成 GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_debugging_consumer 的消费者组,该参数只对非容器环境生效 manageable: false # 是否可管理,默认 false, 开启后 Spring 容器中将多一个 WorkflowManageService 的 Bean,可调用受限访问接口 broadcast: # 关于 Starter 中监听引擎广播的事件相关配置 - enable-filter-application-name: false # 过滤广播事件,只接收来自指定应用名的创建的流程的广播事件,默认 false,不进行过滤。如果为 true,则将配合 filter-application-names 参数进行广播事件的过滤。该过滤功能的前提是使用了 1.3.3 及以上版本的 workflow-engine-api.jar + enable-filter-application-name: false # 过滤广播事件,只接收来自指定应用名的创建的流程的广播事件,默认 false,不进行过滤。如果为 true,则将配合 filter-application-names 参数进行广播事件的过滤。该过滤功能的前提是使用了 1.4.0 及以上版本的 workflow-engine-spring-boot-starter.jar filter-application-names: # 配合 enable-filter-application-name 属性,当它为 true 时,该参数生效。设置的值为需要消费的 MQ 事件 - 'workflow-engine' enable-filter-definition-key: false # 过滤广播事件,只接收指定流程定义的创建的广播事件,默认 false,不进行过滤。如果为 true,则将配合 filter-process-definition-keys 参数进行广播事件的过滤。 From d44c9a2a135782b32b3d84a96a69d3da05c9fbf1 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 13:48:06 +0800 Subject: [PATCH 114/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=B8=80=E4=BA=9B=E7=B1=BB=E5=90=8D=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=9B=B8=E5=85=B3=E6=97=A5=E5=BF=97=E6=89=93?= =?UTF-8?q?=E5=8D=B0=EF=BC=8C=E5=92=8C=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....java => BroadcastListenerProperties.java} | 6 ++-- .../StarterBroadcastMQConfiguration.java | 4 +-- ...orkflowEngineStarterAutoConfiguration.java | 32 +++++++++---------- .../WorkflowEngineStarterProperties.java | 6 ++-- .../handler/execute/ListenerExecutor.java | 5 +-- .../interceptor/ExecuteInterceptor.java | 3 +- .../execute/interceptor/ExecutorInvoker.java | 12 ++++++- .../interceptor/FailBackInterceptor.java | 3 +- .../interceptor/FailFastInterceptor.java | 5 +-- .../interceptor/FailOverInterceptor.java | 28 ++++++++-------- .../execute/interceptor/LogInterceptor.java | 11 ++++--- ...ava => AbstractInnerWorkflowListener.java} | 24 +++++++------- .../consumer/InnerActivityEventListener.java | 10 +++--- .../consumer/InnerInstanceEventListener.java | 10 +++--- .../InnerNotificationEventListener.java | 11 ++++--- .../consumer/InnerTaskEventListener.java | 11 ++++--- ...stener.java => InnerWorkflowListener.java} | 2 +- .../WorkflowEngineBroadcastEventListener.java | 7 ++-- .../filter/InnerFilterDefinitionKey.java | 4 +-- .../filter/InnerFilterExtension.java | 2 +- .../filter/InnerFilterMQOwnerShip.java | 4 +-- ...WorkflowEngineStarterDefaultMQMonitor.java | 2 +- 22 files changed, 113 insertions(+), 89 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/{BroadcastListenerConfigurationProperties.java => BroadcastListenerProperties.java} (92%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/{AbstractWorkflowListener.java => AbstractInnerWorkflowListener.java} (74%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/{WorkflowListener.java => InnerWorkflowListener.java} (86%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java similarity index 92% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java index 5ae6662da..2fedca4e8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerConfigurationProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java @@ -17,11 +17,11 @@ import static cn.axzo.workflow.starter.common.enums.FailHandleTypeEnum.FAIL_OVER * @author wangli * @since 2024/6/4 14:14 */ -public class BroadcastListenerConfigurationProperties { +public class BroadcastListenerProperties { /** * 是否开启根据应用名过滤 MQ 事件 *

- * 如果为 true 时,在不对 {@link BroadcastListenerConfigurationProperties#filterApplicationNames} 设任何值时,默认会将当前应用名加入进去 + * 如果为 true 时,在不对 {@link BroadcastListenerProperties#filterApplicationNames} 设任何值时,默认会将当前应用名加入进去 */ private Boolean enableFilterApplicationName = false; @@ -47,7 +47,7 @@ public class BroadcastListenerConfigurationProperties { /** * 过滤出 MQ 事件中包含这些业务 ID 的事件 *

- * 只有当 {@link BroadcastListenerConfigurationProperties#enableFilterDefinitionKey} 才生效 + * 只有当 {@link BroadcastListenerProperties#enableFilterDefinitionKey} 才生效 *

* 注意: 如果 enableFilterDefinitionKey = true,但该属性集合为空, 将不会过滤任何消息 */ diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index f56712e9b..f79528a62 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -9,7 +9,7 @@ import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.handler.filter.global.BroadcastMessageQueueFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKey; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; @@ -118,7 +118,7 @@ public class StarterBroadcastMQConfiguration { @Bean public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, - List listenerProvider) { + List listenerProvider) { return new WorkflowEngineBroadcastEventListener(eventConsumer, workflowEngineStarterProperties, listenerProvider); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index ff117e362..4b6982e5c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -20,7 +20,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; import cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController; import org.apache.commons.lang3.StringUtils; @@ -68,35 +68,35 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean - public WorkflowListener innerProcessEventListener(ListenerExecutor executor, - ObjectProvider> handlerProvider, - ObjectProvider> filterProvider) { + public InnerWorkflowListener innerProcessEventListener(ListenerExecutor executor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { return new InnerInstanceEventListener(executor, handlerProvider, filterProvider); } @Bean - public WorkflowListener innerActivityEventListener(ListenerExecutor executor, - ObjectProvider> handlerProvider, - ObjectProvider> filterProvider) { + public InnerWorkflowListener innerActivityEventListener(ListenerExecutor executor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { return new InnerActivityEventListener(executor, handlerProvider, filterProvider); } @Bean - public WorkflowListener innerTaskEventListener(ListenerExecutor executor, - ObjectProvider> handlerProvider, - ObjectProvider> filterProvider) { + public InnerWorkflowListener innerTaskEventListener(ListenerExecutor executor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { return new InnerTaskEventListener(executor, handlerProvider, filterProvider); } @Bean - public WorkflowListener innerNotificationEventListener(ListenerExecutor executor, - ObjectProvider> handlerProvider, - ObjectProvider> filterProvider) { + public InnerWorkflowListener innerNotificationEventListener(ListenerExecutor executor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { return new InnerNotificationEventListener(executor, handlerProvider, filterProvider); } private ExecuteInterceptor getFailInterceptor(WorkflowEngineStarterProperties starterProperties) { - BroadcastListenerConfigurationProperties listenerRetry = starterProperties.getBroadcast(); + BroadcastListenerProperties listenerRetry = starterProperties.getBroadcast(); FailHandleTypeEnum failHandleType = listenerRetry.getFailHandleType(); log.info("workflow engine starter fail handle type : {}", failHandleType); switch (failHandleType) { @@ -107,9 +107,7 @@ public class WorkflowEngineStarterAutoConfiguration { return new FailFastInterceptor(); case FAIL_OVER: default: - return new FailOverInterceptor(listenerRetry.getNumOfRetries(), - listenerRetry.getWaitTimeInMs(), - listenerRetry.getWaitIncreaseFactor()); + return new FailOverInterceptor(starterProperties.getBroadcast()); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 4b8394d93..b17826e58 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -50,7 +50,7 @@ public class WorkflowEngineStarterProperties { * 监听流程引擎广播的处理器,异常后的重试相关策略及配置 */ @NestedConfigurationProperty - private BroadcastListenerConfigurationProperties broadcast = new BroadcastListenerConfigurationProperties(); + private BroadcastListenerProperties broadcast = new BroadcastListenerProperties(); public Boolean getManageable() { return manageable; @@ -76,11 +76,11 @@ public class WorkflowEngineStarterProperties { this.invokeMode = invokeMode; } - public BroadcastListenerConfigurationProperties getBroadcast() { + public BroadcastListenerProperties getBroadcast() { return broadcast; } - public void setBroadcast(BroadcastListenerConfigurationProperties broadcast) { + public void setBroadcast(BroadcastListenerProperties broadcast) { this.broadcast = broadcast; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java index fed2de014..300f9c05f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/ListenerExecutor.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.handler.execute; import cn.axzo.framework.domain.ServiceException; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.handler.execute.interceptor.ExecuteInterceptor; import java.util.List; @@ -14,8 +15,8 @@ public final class ListenerExecutor { this.firstExecuteInterceptor = initInterceptorChain(chain); } - public void execute(Consumer command, T t) { - firstExecuteInterceptor.execute(this, command, t); + public void execute(Consumer command, EventConsumer.Context context, T t) { + firstExecuteInterceptor.execute(this, command, context, t); } private ExecuteInterceptor initInterceptorChain(List chain) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java index fd63c037d..c7767f514 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecuteInterceptor.java @@ -1,12 +1,13 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; public interface ExecuteInterceptor { - void execute(ListenerExecutor executor, Consumer consumer, T t); + void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t); ExecuteInterceptor getNext(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java index 838932627..0cbb6c611 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/ExecutorInvoker.java @@ -1,13 +1,23 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Objects; import java.util.function.Consumer; public final class ExecutorInvoker extends AbstractListenerInterceptor { + private static final Logger log = LoggerFactory.getLogger(ExecutorInvoker.class); + @Override - public void execute(ListenerExecutor executor, Consumer consumer, T t) { + public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { + if (Objects.isNull(consumer)) { + log.warn("Unsupported message eventCode type, Please check message producer"); + return; + } consumer.accept(t); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java index b446fd0ba..cc3cebea7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailBackInterceptor.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import java.util.function.Consumer; @@ -9,7 +10,7 @@ import java.util.function.Consumer; */ public final class FailBackInterceptor extends AbstractListenerInterceptor { @Override - public void execute(ListenerExecutor executor, Consumer consumer, T t) { + public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { throw new UnsupportedOperationException("FailBackInterceptor"); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java index f9eaba79c..bd432e078 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.common.exception.WorkflowListenerExecutionException; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; @@ -11,9 +12,9 @@ import java.util.function.Consumer; public final class FailFastInterceptor extends AbstractListenerInterceptor { @Override - public void execute(ListenerExecutor executor, Consumer consumer, T t) { + public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { try { - getNext().execute(executor, consumer, t); + getNext().execute(executor, consumer, context, t); } catch (Exception e) { throw new WorkflowListenerExecutionException( "Failed to invoke the method " diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index b605c5c12..573f16950 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -1,5 +1,7 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.workflow.starter.BroadcastListenerProperties; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -10,48 +12,46 @@ import java.util.function.Consumer; * 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常 */ public final class FailOverInterceptor extends AbstractListenerInterceptor { - - private static final Logger LOGGER = LoggerFactory.getLogger(FailOverInterceptor.class); + private static final Logger log = LoggerFactory.getLogger(FailOverInterceptor.class); private int numOfRetries = 3; - private int waitTimeInMs = 50; - private int waitIncreaseFactor = 5; + private int waitTimeInMs = 1500; + private int waitIncreaseFactor = 3; public FailOverInterceptor() { } - public FailOverInterceptor(int numOfRetries, int waitTimeInMs, int waitIncreaseFactor) { - this.numOfRetries = 0 == Math.abs(numOfRetries) ? this.numOfRetries : Math.abs(numOfRetries); - this.waitTimeInMs = Math.abs(waitTimeInMs); - this.waitIncreaseFactor = Math.abs(waitIncreaseFactor); + public FailOverInterceptor(BroadcastListenerProperties broadcast) { + this.numOfRetries = 0 == Math.abs(broadcast.getNumOfRetries()) ? this.numOfRetries : Math.abs(broadcast.getNumOfRetries()); + this.waitTimeInMs = Math.abs(broadcast.getWaitTimeInMs()); + this.waitIncreaseFactor = Math.abs(broadcast.getWaitIncreaseFactor()); } @Override - public void execute(ListenerExecutor executor, Consumer consumer, T t) { + public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { long waitTime = waitTimeInMs; int failedAttempts = 0; do { if (failedAttempts > 0) { - LOGGER.info("Waiting for {} ms before retrying the command.", waitTime); + log.info("Waiting for {} ms before retrying the command.", waitTime); waitBeforeRetry(waitTime); waitTime *= waitIncreaseFactor; } try { - getNext().execute(executor, consumer, t); + getNext().execute(executor, consumer, context, t); return; } catch (Exception e) { - LOGGER.error("Workflow Engine Starter Caught exception: {}", e.getMessage(), e); + log.error("Workflow Engine Starter Caught exception: {}", e.getMessage(), e); } failedAttempts++; } while (failedAttempts <= numOfRetries); -// throw new ServiceException(numOfRetries + " retries failed with Exception. Giving up."); } private void waitBeforeRetry(long waitTime) { try { Thread.sleep(waitTime); } catch (InterruptedException e) { - LOGGER.debug(" interrupted while waiting for a retry."); + log.debug(" interrupted while waiting for a retry."); } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java index 58f82de6b..7228c5fd6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; +import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; +import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StopWatch; @@ -11,15 +13,16 @@ public final class LogInterceptor extends AbstractListenerInterceptor { private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class); @Override - public void execute(ListenerExecutor executor, Consumer consumer, T t) { + public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); - log.debug("--- starting {} ----", executor.getClass().getSimpleName()); + log.debug("--- starting handle mq ---- "); + log.info("messageId: {}, eventCode: {}, messageBody: {}", context.getMsgId(), context.getEventCode().toString(), JSON.toJSONString(t)); try { - getNext().execute(executor, consumer, t); + getNext().execute(executor, consumer, context, t); } finally { stopWatch.stop(); - log.debug("--- {} finished ,timeCost:{} ms ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); + log.debug("--- messageId: {} finished ,timeCost:{} ms ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java similarity index 74% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java index f0c06c3f1..c1ff38997 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java @@ -15,18 +15,24 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; -public abstract class AbstractWorkflowListener, Target> implements WorkflowListener { +public abstract class AbstractInnerWorkflowListener, Target> implements InnerWorkflowListener { - private static final Logger log = LoggerFactory.getLogger(AbstractWorkflowListener.class); + private static final Logger log = LoggerFactory.getLogger(AbstractInnerWorkflowListener.class); + /** + * 接入方对 cn/axzo/workflow/starter/handler/ 包下的 EventHandler 实现 + */ protected final List businessListeners; + /** + * 接入方对 cn/axzo/workflow/starter/handler/filter/ 包下的EventFilter 实现 + */ protected final List businessFilters; - private final ListenerExecutor listenerExecutor; + protected final ListenerExecutor listenerExecutor; - public AbstractWorkflowListener(ListenerExecutor listenerExecutor, - ObjectProvider> handlerProvider, - ObjectProvider> filterProvider) { + public AbstractInnerWorkflowListener(ListenerExecutor listenerExecutor, + ObjectProvider> handlerProvider, + ObjectProvider> filterProvider) { this.listenerExecutor = listenerExecutor; this.businessListeners = getOrderedBusinessListeners(handlerProvider); this.businessFilters = getOrderedBusinessFilters(filterProvider); @@ -56,7 +62,7 @@ public abstract class AbstractWorkflowListener { +public class InnerActivityEventListener extends AbstractInnerWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerActivityEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> @@ -40,8 +40,10 @@ public class InnerActivityEventListener extends AbstractWorkflowListener consumer = null; switch (type) { @@ -60,7 +62,7 @@ public class InnerActivityEventListener extends AbstractWorkflowListener { +public class InnerInstanceEventListener extends AbstractInnerWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerInstanceEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> @@ -40,8 +40,10 @@ public class InnerInstanceEventListener extends AbstractWorkflowListener consumer = null; switch (type) { @@ -66,7 +68,7 @@ public class InnerInstanceEventListener extends AbstractWorkflowListener { +public class InnerNotificationEventListener extends AbstractInnerWorkflowListener { private final static Logger log = LoggerFactory.getLogger(InnerNotificationEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> @@ -38,8 +38,10 @@ public class InnerNotificationEventListener extends AbstractWorkflowListener consumer = null; switch (type) { @@ -67,7 +69,7 @@ public class InnerNotificationEventListener extends AbstractWorkflowListener { +public class InnerTaskEventListener extends AbstractInnerWorkflowListener { private final Logger log = LoggerFactory.getLogger(InnerTaskEventListener.class); public final static Supplier> SUPPORTED_EVENT_CODES_SUPPLIER = () -> @@ -38,8 +38,10 @@ public class InnerTaskEventListener extends AbstractWorkflowListener consumer = null; switch (type) { @@ -58,9 +60,8 @@ public class InnerTaskEventListener extends AbstractWorkflowListener workflowListeners; - public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List workflowListeners) { + private final List workflowListeners; + + public WorkflowEngineBroadcastEventListener(EventConsumer eventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List workflowListeners) { this.eventConsumer = eventConsumer; this.starterProperties = workflowEngineStarterProperties; this.workflowListeners = workflowListeners; @@ -50,7 +51,7 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi return; } - for (WorkflowListener workflowListener : workflowListeners) { + for (InnerWorkflowListener workflowListener : workflowListeners) { if (workflowListener.dispatch(event)) { workflowListener.handleEvent(event, context); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java index c13d1ea00..a08e15f6b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterDefinitionKey.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; -import cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties; +import cn.axzo.workflow.starter.BroadcastListenerProperties; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; @@ -12,7 +12,7 @@ import java.util.Map; import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; /** - * 对 {@link BroadcastListenerConfigurationProperties#filterProcessDefinitionKeys} 的实现 + * 对 {@link BroadcastListenerProperties#filterProcessDefinitionKeys} 的实现 * * @author wangli * @since 2024/6/4 17:06 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java index 83647d8b4..dfb5b3b3a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterExtension.java @@ -36,7 +36,7 @@ public class InnerFilterExtension implements InnerMessageQueueHandleBeforeFilter @Override public boolean doFilter(MessageExt message) { if (businessFilters.isEmpty()) { - log.debug("【{}】business filter is empty", this.getClass().getSimpleName()); + log.debug("【{}】business extension filter is empty", this.getClass().getSimpleName()); return false; } for (BroadcastMessageQueueFilter businessFilter : businessFilters) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java index a20002965..1ccfd2f85 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/InnerFilterMQOwnerShip.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; -import cn.axzo.workflow.starter.BroadcastListenerConfigurationProperties; +import cn.axzo.workflow.starter.BroadcastListenerProperties; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import org.apache.rocketmq.common.message.MessageExt; import org.slf4j.Logger; @@ -12,7 +12,7 @@ import java.util.Map; import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION; /** - * 对 {@link BroadcastListenerConfigurationProperties#filterApplicationNames} 的实现 + * 对 {@link BroadcastListenerProperties#filterApplicationNames} 的实现 * * @author wangli * @since 2024/6/4 17:06 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 0acaccaec..d45561213 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -47,7 +47,7 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { } public void mqWatch() { - log.info("time is :{}", System.currentTimeMillis()); + log.debug("time is :{}", System.currentTimeMillis()); String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); String applicationName = environment.getProperty("spring.application.name"); // 周期性比对 From 254e84654bd4ce97bbe00981966243f51b6bda50 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 13:58:38 +0800 Subject: [PATCH 115/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E9=9C=80=E8=A6=81=E9=87=8D=E8=AF=95=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumer/WorkflowEngineStarterRetryEventListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 7414db959..1eac34b65 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -111,6 +111,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In return expression; } + @SneakyThrows @Override public void onEvent(Event event, EventConsumer.Context context) { log.info("WorkflowEngineClientRetryEventListener onEvent: {}", event.toPrettyJsonString()); @@ -138,7 +139,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In log.error("Event Invoke Exception: {}", cause.getMessage(), cause); if (cause instanceof ConnectException) { // 而只有当网络异常时, 利用 RocketMQ 的重试机制 - throw new RuntimeException(cause); + throw cause; } } } From 395d06f3f9078ab66aae0e3dda747951590612ff Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 13:58:56 +0800 Subject: [PATCH 116/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=BA?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=B0=83=E6=95=B4=20RPC=20MQ=20=E7=9A=84?= =?UTF-8?q?=E9=87=8D=E8=AF=95=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 171a0a84b..e34f52d41 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -161,7 +161,7 @@ public class StarterRPCInvokeMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, - maxReconsumeTimes = 7, // 发布时需调整为 7, 总共耗时在 15min 内 + maxReconsumeTimes = 3, // TODO 发布时需调整为 7, 总共耗时在 15min 内 replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) From c34950a53f8da628cf9ec142c3faf11d3e82d40e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 14:18:56 +0800 Subject: [PATCH 117/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=8C=85=E8=A3=85=20RPC=20=E5=8A=A8=E4=BD=9C=E7=9A=84?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...rkflowEngineStarterRetryEventListener.java | 65 +++++++++---------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 1eac34b65..7d310dd30 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -47,7 +47,25 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In private final String currentApplicationName; private WorkflowCoreService workflowCoreService; private WorkflowManageService workflowManageService; - private final Map methodCache = new HashMap<>(); + private final Map methodCache = new HashMap<>(); + + class InterfaceMapping { + private final Object interfaceObject; + private final Method method; + + public InterfaceMapping(Object interfaceObject, Method method) { + this.interfaceObject = interfaceObject; + this.method = method; + } + + public Object getInterfaceObject() { + return interfaceObject; + } + + public Method getMethod() { + return method; + } + } public WorkflowEngineStarterRetryEventListener(EventConsumer workflowEngineStarterEventConsumer, Environment environment, @@ -75,68 +93,47 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In if (Objects.isNull(feignClient)) { throw new IllegalStateException("WorkflowCoreService 配置错误,没有找到 FeignClient 注解"); } -// String parsedFeignContextUrl = resolveExpression(feignClient.url()); Method[] methods = coreService.getDeclaredMethods(); for (Method method : methods) { - methodCache.put(method.getName(), method); + methodCache.put(method.getName(), new InterfaceMapping(workflowCoreService, method)); } } private void parseWorkflowManageService() { - Class coreService = (Class) workflowManageService.getClass().getGenericInterfaces()[0]; - FeignClient feignClient = AnnotationUtils.findAnnotation(coreService, FeignClient.class); + Class manageService = (Class) workflowManageService.getClass().getGenericInterfaces()[0]; + FeignClient feignClient = AnnotationUtils.findAnnotation(manageService, FeignClient.class); if (Objects.isNull(feignClient)) { throw new IllegalStateException("WorkflowCoreService 配置错误,没有找到 FeignClient 注解"); } -// String parsedFeignContextUrl = resolveExpression(feignClient.url()); - Method[] methods = coreService.getDeclaredMethods(); + Method[] methods = manageService.getDeclaredMethods(); for (Method method : methods) { - methodCache.put(method.getName(), method); + methodCache.put(method.getName(), new InterfaceMapping(workflowManageService, method)); } } - private String resolveExpression(String expression) { - // 假设表达式格式是 ${property:defaultValue} - if (expression != null && expression.startsWith("${") && expression.endsWith("}")) { - String content = expression.substring(2, expression.length() - 1); // 去除 ${ 和 } - String[] parts = content.split(":", 2); // 分割属性和默认值 - String property = parts[0]; - String defaultValue = parts.length > 1 ? parts[1] : null; - // 尝试从环境中获取属性值,如果未找到则使用默认值 - return environment.getProperty(property, defaultValue != null ? defaultValue : ""); - } - // 如果表达式格式不匹配,直接返回原表达式或处理错误情况 - return expression; - } - @SneakyThrows @Override public void onEvent(Event event, EventConsumer.Context context) { log.info("WorkflowEngineClientRetryEventListener onEvent: {}", event.toPrettyJsonString()); WorkflowEngineStarterRpcInvokeDTO dto = event.normalizedData(WorkflowEngineStarterRpcInvokeDTO.class); - Method method = methodCache.getOrDefault(dto.getMethodName(), null); - if (Objects.isNull(method)) { + InterfaceMapping mapping = methodCache.getOrDefault(dto.getMethodName(), null); + if (Objects.isNull(mapping)) { throw new IllegalStateException("Not found method:" + dto.getMethodName()); } try { // 事件处理 RPC 请求, 强制使用同步模式 ThreadUtil.set(SYNC); - Object[] args = convertToActualArgs(method, dto.getParameters()); - log.info("event rpc request args: {}", JSON.toJSONString(args)); - Object invoke; - if (starterProperties.getManageable()) { - invoke = method.invoke(workflowCoreService, args); - } else { - invoke = method.invoke(workflowManageService, args); - } - log.info("Event Invoke Result: {}", JSON.toJSONString(invoke)); + Object[] args = convertToActualArgs(mapping.getMethod(), dto.getParameters()); + log.debug("event rpc request args: {}", JSON.toJSONString(args)); + Object invoke = mapping.getMethod().invoke(mapping.getInterfaceObject(), args); + log.debug("Event Invoke Result: {}", JSON.toJSONString(invoke)); } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 Throwable cause = getRealCause(e); - log.error("Event Invoke Exception: {}", cause.getMessage(), cause); + log.warn("Event Invoke Exception: {}", cause.getMessage(), cause); if (cause instanceof ConnectException) { // 而只有当网络异常时, 利用 RocketMQ 的重试机制 throw cause; From 6a1c796f8afc10104cb72b47d684c5d7729a46f5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 14:46:39 +0800 Subject: [PATCH 118/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20RPC=20Retry=20=E4=B8=AD=20Header=20=E4=BC=9A?= =?UTF-8?q?=E8=A2=AB=E9=87=8D=E5=A4=8D=E8=AE=BE=E7=BD=AE=EF=BC=8C=E5=80=BC?= =?UTF-8?q?=E4=BC=9A=E5=8F=98=E6=88=90=E9=9B=86=E5=90=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterFeignConfiguration.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index d16bc7f37..31cc470aa 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -45,16 +45,6 @@ public class WorkflowEngineStarterFeignConfiguration { return new Retryer.Default(100, SECONDS.toMillis(1), 3); } -// @Bean -// public Feign.Builder workflowEngineStarterFeignBuilder() { -// return WorkflowEngineStarterFeign.builder(); -// } - -// @Bean -// public Targeter workflowEngineStarterFeignTargeter(WorkflowEngineStarterProperties starterProperties) { -// return new WorkflowEngineStarterTargeter(starterProperties); -// } - @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, @Qualifier("workflowEngineStarterEventProducer") EventProducer eventProducer, @@ -80,8 +70,10 @@ public class WorkflowEngineStarterFeignConfiguration { log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); rpcInvokeModeEnum = starterProperties.getInvokeMode(); } - // 通过服务端的校验 + // 重置 header 中的同步异步请求模式 + template.removeHeader(STARTER_INVOKE_MODE); template.header(STARTER_INVOKE_MODE, rpcInvokeModeEnum.name()); + // 通过服务端的校验 Target.HardCodedTarget target = (Target.HardCodedTarget) template.feignTarget(); String apiClassPath = target.type().getName(); if (apiClassPath.contains("cn.axzo.workflow.starter.api")) { From 8ebe67f3149087dd79b3b104545e89955918b1ec Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 14:46:59 +0800 Subject: [PATCH 119/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=97=A5=E5=BF=97=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/feign/ext/ComplexInvokeClient.java | 10 ++++------ .../mq/retry/producer/RpcInvokeEventProducer.java | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index d0f4932a2..6661bf25a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -77,14 +77,13 @@ public class ComplexInvokeClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { - log.info("ComplexInvokeClient execute..."); + log.debug("ComplexInvokeClient execute... Url: {}", request.url()); RpcInvokeModeEnum currentInvokeModeEnum = getInvokeMode(request); - Map> headers = request.headers(); - headers.forEach((k, v) -> log.info("ComplexInvokeClient header: {} = {}", k, v)); + headers.forEach((k, v) -> log.debug("ComplexInvokeClient Header: {} = {}", k, v)); + log.debug("[{}] invoke url: {}", currentInvokeModeEnum, request.url()); if (Objects.equals(SYNC, currentInvokeModeEnum)) { - log.info("[sync] invoke..."); ThreadUtil.clear(); return feignClient.execute(request, options); } @@ -105,7 +104,6 @@ public class ComplexInvokeClient implements Client { * @param request */ private void asyncInvoke(Request request) { - log.info("[async] invoke..."); WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); MethodMetadata metadata = request.requestTemplate().methodMetadata(); event.setClassName(metadata.targetType().getName()); @@ -114,7 +112,7 @@ public class ComplexInvokeClient implements Client { List args = new ArrayList<>(); event.setParameters(args); buildArgs(request, metadata, args); - + log.debug("[async-invoke] sourceEvent: {}", JSON.toJSONString(event)); eventProducer.send(WORKFLOW_ENGINE_STARTER, event); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index 8851fb25d..b61406bef 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -49,7 +49,7 @@ public class RpcInvokeEventProducer extends RocketMQEventProducer { @Override public void send(@NonNull Event event, @NonNull Context context) { - log.info("发送事件内容:{}", event.toPrettyJsonString()); + log.info("发送事件内容: {}", event.toPrettyJsonString()); if (sendBeforeCallback != null) { sendBeforeCallback.accept(event, context); } From 76ce62bd8a2727b36c9c5a02d5dcb206dc35436c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 15:13:49 +0800 Subject: [PATCH 120/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=AE=BE=E7=BD=AE=20Request=20header=20=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=B0=83=E7=94=A8=E6=A8=A1=E5=BC=8F=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/ComplexInvokeClient.java | 1 - ...rkflowEngineStarterFeignConfiguration.java | 24 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 6661bf25a..6c12cb58a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -84,7 +84,6 @@ public class ComplexInvokeClient implements Client { log.debug("[{}] invoke url: {}", currentInvokeModeEnum, request.url()); if (Objects.equals(SYNC, currentInvokeModeEnum)) { - ThreadUtil.clear(); return feignClient.execute(request, options); } asyncInvoke(request); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 31cc470aa..757418823 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.azxo.framework.common.constatns.Constants; import feign.Client; import feign.RequestInterceptor; +import feign.RequestTemplate; import feign.Retryer; import feign.Target; import feign.codec.Decoder; @@ -64,15 +65,7 @@ public class WorkflowEngineStarterFeignConfiguration { return template -> { // 接入应用上报 template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); - // 接口的同步异步模式 - RpcInvokeModeEnum rpcInvokeModeEnum = ThreadUtil.get(); - if (Objects.isNull(rpcInvokeModeEnum)) { - log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); - rpcInvokeModeEnum = starterProperties.getInvokeMode(); - } - // 重置 header 中的同步异步请求模式 - template.removeHeader(STARTER_INVOKE_MODE); - template.header(STARTER_INVOKE_MODE, rpcInvokeModeEnum.name()); + resetInvokeMode(starterProperties, template); // 通过服务端的校验 Target.HardCodedTarget target = (Target.HardCodedTarget) template.feignTarget(); String apiClassPath = target.type().getName(); @@ -85,6 +78,19 @@ public class WorkflowEngineStarterFeignConfiguration { }; } + private void resetInvokeMode(WorkflowEngineStarterProperties starterProperties, RequestTemplate template) { + // 接口的同步异步模式 + RpcInvokeModeEnum rpcInvokeModeEnum = ThreadUtil.get(); + ThreadUtil.clear(); + if (Objects.isNull(rpcInvokeModeEnum)) { + log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); + rpcInvokeModeEnum = starterProperties.getInvokeMode(); + } + // 重置 header 中的同步异步请求模式 + template.removeHeader(STARTER_INVOKE_MODE); + template.header(STARTER_INVOKE_MODE, rpcInvokeModeEnum.name()); + } + @Bean public FeignBuilderCustomizer workflowEngineFeignBuilderCustomizer() { From 529d5528a4a9ea0b2e9f9c6ef738a3b938689c6f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 15:27:58 +0800 Subject: [PATCH 121/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=AE=BE=E7=BD=AE=20Request=20header=20=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=B0=83=E7=94=A8=E6=A8=A1=E5=BC=8F=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/WorkflowEngineStarterFeignConfiguration.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 757418823..bf8b1965b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -22,7 +22,10 @@ import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; +import java.util.Collection; +import java.util.Collections; import java.util.Objects; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; @@ -82,7 +85,8 @@ public class WorkflowEngineStarterFeignConfiguration { // 接口的同步异步模式 RpcInvokeModeEnum rpcInvokeModeEnum = ThreadUtil.get(); ThreadUtil.clear(); - if (Objects.isNull(rpcInvokeModeEnum)) { + Collection invokeModeInHeader = template.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.emptyList()); + if (Objects.isNull(rpcInvokeModeEnum) && CollectionUtils.isEmpty(invokeModeInHeader)) { log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); rpcInvokeModeEnum = starterProperties.getInvokeMode(); } From e28e8071c41b99daca87fdfa785cf0a6f822eed1 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 15:56:11 +0800 Subject: [PATCH 122/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=AE=BE=E7=BD=AE=20Request=20header=20=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=B0=83=E7=94=A8=E6=A8=A1=E5=BC=8F=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterFeignConfiguration.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index bf8b1965b..a3f1aef28 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -82,16 +82,19 @@ public class WorkflowEngineStarterFeignConfiguration { } private void resetInvokeMode(WorkflowEngineStarterProperties starterProperties, RequestTemplate template) { + Collection invokeModeInHeader = template.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.emptyList()); + template.removeHeader(STARTER_INVOKE_MODE); // 接口的同步异步模式 RpcInvokeModeEnum rpcInvokeModeEnum = ThreadUtil.get(); ThreadUtil.clear(); - Collection invokeModeInHeader = template.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.emptyList()); - if (Objects.isNull(rpcInvokeModeEnum) && CollectionUtils.isEmpty(invokeModeInHeader)) { - log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); - rpcInvokeModeEnum = starterProperties.getInvokeMode(); + if (Objects.isNull(rpcInvokeModeEnum)) { + if (CollectionUtils.isEmpty(invokeModeInHeader)) { + log.debug("Without calling the async or sync methods of the WorkflowCoreService, the default configuration in WorkflowEngineStarterProperties will be loaded."); + rpcInvokeModeEnum = starterProperties.getInvokeMode(); + } else { + rpcInvokeModeEnum = RpcInvokeModeEnum.valueOf(invokeModeInHeader.iterator().next()); + } } - // 重置 header 中的同步异步请求模式 - template.removeHeader(STARTER_INVOKE_MODE); template.header(STARTER_INVOKE_MODE, rpcInvokeModeEnum.name()); } From 07679910d3d61fbf42e8d76964f877c150147241 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 16:41:56 +0800 Subject: [PATCH 123/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E6=97=A5=E5=BF=97=EF=BC=8C=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E6=B6=88=E9=99=A4=E4=B8=80=E4=BA=9B=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/StarterRPCInvokeMQConfiguration.java | 7 ++++--- .../handler/execute/interceptor/FailOverInterceptor.java | 6 +++++- .../consumer/WorkflowEngineStarterRetryEventListener.java | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index e34f52d41..adc53b377 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -53,6 +53,7 @@ public class StarterRPCInvokeMQConfiguration { public static final String DEFAULT_MODULE = "workflowEngine"; public static final String DEFAULT_EVENT = "topic_workflow_engine_"; + private static final String MODULE_NAME_SUFFIX = "_rpc_retry_starter"; @Value("${spring.application.name}") private String applicationName; @@ -71,7 +72,7 @@ public class StarterRPCInvokeMQConfiguration { public EventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { return new RpcInvokeEventProducer(rocketMQTemplate, DEFAULT_MODULE, - applicationName + "_WE_Starter", + applicationName + MODULE_NAME_SUFFIX, EventProducer.Context.builder() .meta(RocketMQEventProducer.RocketMQMessageMeta.builder() .topic(DEFAULT_EVENT + activeProfile) @@ -136,7 +137,7 @@ public class StarterRPCInvokeMQConfiguration { @ConditionalOnMissingBean(name = "workflowEngineStarterEventHandlerRepository") public EventHandlerRepository workflowEngineStarterEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { - log.warn("MQ, handle warning {}", logText, ex); + log.warn("MQ event handle repository has exception record: {}", logText, ex); if (Objects.nonNull(ex)) { throw new RuntimeException(ex); } @@ -153,7 +154,7 @@ public class StarterRPCInvokeMQConfiguration { log.info("WorkflowEngineStarter RPC MQ, handled event: {}", event.toPrettyJsonString()); } }; - return new DefaultEventConsumer(applicationName + "Starter", workflowEngineStarterEventHandlerRepository, callback); + return new DefaultEventConsumer(applicationName + MODULE_NAME_SUFFIX, workflowEngineStarterEventHandlerRepository, callback); } @Component diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index 573f16950..dd4b54d62 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -41,7 +41,11 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { getNext().execute(executor, consumer, context, t); return; } catch (Exception e) { - log.error("Workflow Engine Starter Caught exception: {}", e.getMessage(), e); + if (failedAttempts == numOfRetries) { + log.error("Workflow Engine Starter caught exception: {}", e.getMessage(), e); + } else { + log.warn("Workflow Engine Starter caught exception: {}", e.getMessage(), e); + } } failedAttempts++; } while (failedAttempts <= numOfRetries); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 7d310dd30..5b0983366 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -133,7 +133,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 Throwable cause = getRealCause(e); - log.warn("Event Invoke Exception: {}", cause.getMessage(), cause); + log.warn("onEvent Invoke root exception cause by: {}", cause.getMessage(), cause); if (cause instanceof ConnectException) { // 而只有当网络异常时, 利用 RocketMQ 的重试机制 throw cause; From ec52b1ac680ccef0156a1e2ff3ae057754d1e8f6 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 17:56:50 +0800 Subject: [PATCH 124/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=BE=9B=E4=B8=9A=E5=8A=A1=E6=96=B9=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MessageNotificationEventHandler.java | 28 +++++++++---------- .../handler/ProcessActivityEventHandler.java | 16 +++++------ .../handler/ProcessInstanceEventHandler.java | 24 ++++++++-------- .../handler/ProcessTaskEventHandler.java | 8 +++--- .../global/BroadcastMessageQueueFilter.java | 2 +- .../filter/BasicMessageQueueFilter.java | 8 ++++-- 6 files changed, 45 insertions(+), 41 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java index 8a4528bbe..5230cb6c8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java @@ -14,57 +14,57 @@ public interface MessageNotificationEventHandler extends Ordered { /** * 站内信推送 * - * @param messagePushDTO + * @param dto */ - default void pushNotice(MessagePushDTO messagePushDTO) { + default void pushNotice(MessagePushDTO dto) { } /** * 待办推送 * - * @param messagePushDTO + * @param dto */ - default void pushPending(MessagePushDTO messagePushDTO) { + default void pushPending(MessagePushDTO dto) { } /** * 完成待办 * - * @param messagePushDTO + * @param dto */ - default void completePending(MessagePushDTO messagePushDTO) { + default void completePending(MessagePushDTO dto) { } /** * 审批失败,恢复待办 * - * @param messagePushDTO + * @param dto */ - default void rollbackPending(MessagePushDTO messagePushDTO) { + default void rollbackPending(MessagePushDTO dto) { } /** * 抄送流程 * - * @param messagePushDTO + * @param dto */ - default void carbonCopy(MessagePushDTO messagePushDTO) { + default void carbonCopy(MessagePushDTO dto) { } /** * 完成抄送 * - * @param messagePushDTO + * @param dto */ - default void carbonCopyComplete(MessagePushDTO messagePushDTO) { + default void carbonCopyComplete(MessagePushDTO dto) { } /** * 短信推送 * - * @param messagePushDTO + * @param dto */ - default void pushSms(MessagePushDTO messagePushDTO) { + default void pushSms(MessagePushDTO dto) { } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java index f6f62b9e8..fa568e4e0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java @@ -19,32 +19,32 @@ public interface ProcessActivityEventHandler extends Ordered { /** * 节点已启动 * - * @param activityDTO 入参 + * @param dto 入参 */ - default void onStart(ProcessActivityDTO activityDTO) { + default void onStart(ProcessActivityDTO dto) { } /** * 节点等待业务指定审批人 * - * @param activityDTO 入参 + * @param dto 入参 */ - default void onWaitAssignee(ProcessActivityDTO activityDTO) { + default void onWaitAssignee(ProcessActivityDTO dto) { } /** * 节点已完成 * - * @param activityDTO 入参 + * @param dto 入参 */ - default void onTake(ProcessActivityDTO activityDTO) { + default void onTake(ProcessActivityDTO dto) { } /** * 节点已取消 * - * @param activityDTO 入参 + * @param dto 入参 */ - default void onEnd(ProcessActivityDTO activityDTO) { + default void onEnd(ProcessActivityDTO dto) { } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java index a0d9d33bc..96748a320 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java @@ -16,17 +16,17 @@ public interface ProcessInstanceEventHandler extends Ordered { /** * 流程实例创建成功后回调 * - * @param processInstanceDTO + * @param dto */ - default void onCreated(ProcessInstanceDTO instanceDTO) { + default void onCreated(ProcessInstanceDTO dto) { } /** * 流程实例开始运行后回调 * - * @param processInstanceDTO + * @param dto */ - default void onStarted(ProcessInstanceDTO instanceDTO) { + default void onStarted(ProcessInstanceDTO dto) { } /** @@ -34,9 +34,9 @@ public interface ProcessInstanceEventHandler extends Ordered { *

* 注意: 该接口表明流程已经走完正向逻辑,正向逻辑比如:通过、同意等 * - * @param instanceDTO + * @param dto */ - default void onCompleted(ProcessInstanceDTO instanceDTO) { + default void onCompleted(ProcessInstanceDTO dto) { } /** @@ -44,9 +44,9 @@ public interface ProcessInstanceEventHandler extends Ordered { *

* 撤回只有发起人能触发 * - * @param instanceDTO + * @param dto */ - default void onCancelled(ProcessInstanceDTO instanceDTO) { + default void onCancelled(ProcessInstanceDTO dto) { } /** @@ -54,9 +54,9 @@ public interface ProcessInstanceEventHandler extends Ordered { *

* 审批过程中,有一个审批人或者有节点配置的是“自动驳回”,都能触发该事件。 * - * @param instanceDTO + * @param dto */ - default void onRejected(ProcessInstanceDTO instanceDTO) { + default void onRejected(ProcessInstanceDTO dto) { } /** @@ -64,8 +64,8 @@ public interface ProcessInstanceEventHandler extends Ordered { *

* 一般由接入方主动触发,比如调用了 {@link ProcessInstanceApi#abortProcessInstance(BpmnProcessInstanceAbortDTO)} 方法等 * - * @param instanceDTO + * @param dto */ - default void onAborted(ProcessInstanceDTO instanceDTO) { + default void onAborted(ProcessInstanceDTO dto) { } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java index 220eb2da9..700548219 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java @@ -16,13 +16,13 @@ public interface ProcessTaskEventHandler extends Ordered { /** * 用户任务已指派审核人 */ - default void onAssigned(ProcessTaskDTO taskDTO) { + default void onAssigned(ProcessTaskDTO dto) { } /** * 用户任务已创建,未指派审核人 */ - default void onCreated(ProcessTaskDTO taskDTO) { + default void onCreated(ProcessTaskDTO dto) { } /** @@ -30,7 +30,7 @@ public interface ProcessTaskEventHandler extends Ordered { *

* 仅审核通过一个用户任务时触发, 如果任务是驳回了, 则直接走实例撤回事件 */ - default void onCompleted(ProcessTaskDTO taskDTO) { + default void onCompleted(ProcessTaskDTO dto) { } /** @@ -38,6 +38,6 @@ public interface ProcessTaskEventHandler extends Ordered { *

* 删除不代表驳回或拒绝,因为通过也会走该事件 */ - default void onDeleted(ProcessTaskDTO taskDTO) { + default void onDeleted(ProcessTaskDTO dto) { } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java index f3426179f..d17283353 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/global/BroadcastMessageQueueFilter.java @@ -16,7 +16,7 @@ public interface BroadcastMessageQueueFilter extends Ordered { /** * @param message MQ 消息元数据 * @param jsonData MQ 消息中的 payload,是 JSON 格式的字符串 - * @return + * @return 返回 true 时,将跳过该 {@link MessageExt} 消息,不进行消费 */ boolean doFilter(MessageExt message, String jsonData); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java index 8e7f60bf7..cfc8220d7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import org.apache.rocketmq.common.message.MessageExt; import org.springframework.core.Ordered; /** @@ -15,10 +17,12 @@ public interface BasicMessageQueueFilter extends Ordered { * 基于具体的 {@link Event.EventCode#module} 下的自定义的 MQ 过滤器 * * @param event 事件原对象 + * @param context event 上下文对象,包含 msgId,headers 等信息,其中 headers 有 MQ 消息归属哪个应用, + * 使用 {@code MQ_OWNERSHIP_APPLICATION} 获取值 * @param data payload 被转换后的目标对象 - * @return + * @return 返回 true 时,将跳过该 {@link Event} 消息,不进行消费 */ - default boolean doFilter(Event event, T data) { + default boolean doFilter(Event event, EventConsumer.Context context, T data) { return false; } } From 124b73888cbeb59c5059cedc2adf83527838c11d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 17:57:04 +0800 Subject: [PATCH 125/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20Server=20=E6=A8=A1=E5=9D=97=E4=B8=8B=E5=BC=95?= =?UTF-8?q?=E5=85=A5=E7=9A=84=20Starter=20=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-server/pom.xml | 4 ++-- .../server/controller/web/TestController.java | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/workflow-engine-server/pom.xml b/workflow-engine-server/pom.xml index cbe4dcf96..823736ca7 100644 --- a/workflow-engine-server/pom.xml +++ b/workflow-engine-server/pom.xml @@ -21,10 +21,10 @@ 3.25.0 - + cn.axzo.framework axzo-web-spring-boot-starter diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index f8e0c34e7..a3fe66874 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -13,8 +13,6 @@ import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.support.FlowNodeForecastService; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; -import cn.axzo.workflow.starter.api.WorkflowCoreService; -import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.azxo.framework.common.model.CommonResponse; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; @@ -68,10 +66,10 @@ public class TestController { private ProcessInstanceApi processInstanceApi; @Autowired private BpmnProcessInstanceService bpmnProcessInstanceService; - @Autowired - private WorkflowCoreService workflowCoreService; - @Autowired - private WorkflowManageService workflowManageService; +// @Autowired +// private WorkflowCoreService workflowCoreService; +// @Autowired +// private WorkflowManageService workflowManageService; @RepeatSubmit @GetMapping("/test") @@ -138,7 +136,7 @@ public class TestController { return CommonResponse.success(true); } - @GetMapping("/create") + /*@GetMapping("/create") public CommonResponse test5(@RequestParam(required = false) Boolean sync) { BpmnProcessInstanceCreateDTO dto = new BpmnProcessInstanceCreateDTO(); dto.setProcessDefinitionKey("1"); @@ -250,5 +248,5 @@ public class TestController { public CommonResponse> test11() { List tenantIds = workflowManageService.sync().getTenantIds(); return CommonResponse.success(tenantIds); - } + }*/ } From fdf2c7b4a74cc142359612638ab9e75bd42c7895 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 18:01:22 +0800 Subject: [PATCH 126/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E7=BC=96=E8=AF=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/broadcast/consumer/AbstractInnerWorkflowListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java index c1ff38997..0956606c0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/AbstractInnerWorkflowListener.java @@ -61,7 +61,7 @@ public abstract class AbstractInnerWorkflowListener Date: Thu, 13 Jun 2024 18:36:29 +0800 Subject: [PATCH 127/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=B2=BE=E7=BB=86=E5=8C=96=20EventCode=20=E7=9A=84?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E8=BF=87=E6=BB=A4=E5=99=A8=E7=9A=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../broadcast/filter/BasicMessageQueueFilter.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java index cfc8220d7..aa3a31af6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/filter/BasicMessageQueueFilter.java @@ -2,7 +2,7 @@ package cn.axzo.workflow.starter.mq.broadcast.filter; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; -import org.apache.rocketmq.common.message.MessageExt; +import cn.axzo.workflow.common.constant.BpmnConstants; import org.springframework.core.Ordered; /** @@ -16,10 +16,13 @@ public interface BasicMessageQueueFilter extends Ordered { /** * 基于具体的 {@link Event.EventCode#module} 下的自定义的 MQ 过滤器 * - * @param event 事件原对象 - * @param context event 上下文对象,包含 msgId,headers 等信息,其中 headers 有 MQ 消息归属哪个应用, - * 使用 {@code MQ_OWNERSHIP_APPLICATION} 获取值 - * @param data payload 被转换后的目标对象 + * @param event 事件原对象 + * @param context event 上下文对象,包含 msgId,headers 等信息,其中
+ * 有 MQ 消息归属哪个应用,使用 {@link BpmnConstants#MQ_OWNERSHIP_APPLICATION} 获取值;
+ * 还有 MQ 消息归属哪个业务 ID,使用 {@link BpmnConstants#MQ_OWNERSHIP_PROCESS_DEFINITION_KEY} 获取值. + *

获取归属应用示例: + *

String owner_application = new String(context.getHeaders().getOrDefault(MQ_OWNERSHIP_APPLICATION, new byte[0]), StandardCharsets.UTF_8);
+ * @param data payload 被转换后的目标对象 * @return 返回 true 时,将跳过该 {@link Event} 消息,不进行消费 */ default boolean doFilter(Event event, EventConsumer.Context context, T data) { From 51aa2a0511f7ae61286a60bf10ea4f6cbee0dfc3 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 18:36:50 +0800 Subject: [PATCH 128/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E9=9D=9E=20default=20=E7=9A=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/handler/ProcessActivityEventHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java index fa568e4e0..de90322da 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java @@ -21,8 +21,7 @@ public interface ProcessActivityEventHandler extends Ordered { * * @param dto 入参 */ - default void onStart(ProcessActivityDTO dto) { - } + void onStart(ProcessActivityDTO dto); /** * 节点等待业务指定审批人 From f0466b80096a7f3db921cbdb3b2d045edfc25676 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 18:38:13 +0800 Subject: [PATCH 129/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E4=B8=80=E4=BA=9B=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java | 2 +- .../workflow/starter/handler/ProcessActivityEventHandler.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index adc53b377..3074042c9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -162,7 +162,7 @@ public class StarterRPCInvokeMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, - maxReconsumeTimes = 3, // TODO 发布时需调整为 7, 总共耗时在 15min 内 + maxReconsumeTimes = 7, // 发布时需调整为 7, 总共耗时在 15min 内 replyTimeout = 10000, nameServer = "${rocketmq.name-server}" ) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java index de90322da..fa568e4e0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java @@ -21,7 +21,8 @@ public interface ProcessActivityEventHandler extends Ordered { * * @param dto 入参 */ - void onStart(ProcessActivityDTO dto); + default void onStart(ProcessActivityDTO dto) { + } /** * 节点等待业务指定审批人 From a4b34c84999c1eb05e35025ab563685fcfa6a81f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 13 Jun 2024 18:46:21 +0800 Subject: [PATCH 130/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=B8=80=E4=BA=9B=E6=B3=A8=E9=87=8A=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=96=B9=E6=B3=95=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/starter/BroadcastListenerProperties.java | 4 ++-- .../workflow/starter/WorkflowEngineStarterProperties.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java index 2fedca4e8..412cc41a6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java @@ -56,9 +56,9 @@ public class BroadcastListenerProperties { /** * 失败处理策略: *
-     * 1、FAIL_OVER, 当前listener执行出错,忽略继续往下执行,可配置重试相关参数,不抛出异常(默认策略)
+     * 1、FAIL_OVER, 当前listener执行出错,在经历重试后,不抛出异常,忽略继续往下执行(默认策略)
      * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行
-     * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持
+     * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持
      * 
*/ private FailHandleTypeEnum failHandleType = FAIL_OVER; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index b17826e58..e62efe7dd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -19,7 +19,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; @ConfigurationProperties(prefix = "workflow.engine.starter") public class WorkflowEngineStarterProperties { /** - * 是否可管理 + * 特殊用途,不建议接入方使用 */ private Boolean manageable = false; From 27be98a84307bc5241feb491c5f2b820fdffafce Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 09:35:07 +0800 Subject: [PATCH 131/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AF=B9?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E8=BF=87=E7=A8=8B=E4=B8=AD=E7=9A=84=E2=80=9C?= =?UTF-8?q?=E4=BA=BA=E2=80=9D=E7=9A=84=E9=83=A8=E5=88=86=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=B7=BB=E5=8A=A0=E5=B1=9E=E6=80=A7=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/request/bpmn/task/BpmnTaskDelegateAssigner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java index 899584415..cf11bb52c 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java @@ -44,7 +44,7 @@ public class BpmnTaskDelegateAssigner implements Serializable { private static final long serialVersionUID = -8106887960942113552L; /** - * 审核人标识, 应该必传 + * 【废弃】审核人标识, 应该必传 *

* 枢智:用户 ID * 安心筑:身份 ID @@ -53,7 +53,7 @@ public class BpmnTaskDelegateAssigner implements Serializable { private String assignee; /** - * 审核人标识扩展信息 + * 【废弃】审核人标识扩展信息 *

* 枢智:可不传 * 安心筑:身份 Type 应该必传 From e7d435f3474935ab94e8d56f2fbed34d924b221a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 10:16:26 +0800 Subject: [PATCH 132/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=AF=B9=20ConsumerContext=20=E7=9A=84=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=80=BB=E8=BE=91=EF=BC=8C=E9=81=BF=E5=85=8D=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=BA=95=E5=B1=82=E6=8A=9B=E5=87=BA=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../execute/interceptor/FailOverInterceptor.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index dd4b54d62..b4d2cb1ec 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -29,6 +29,8 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { @Override public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { + // 避免组件抛出“程序处理超时”的异常信息 + context.setMaxAllowElapsedMillis(calc() + 500L); long waitTime = waitTimeInMs; int failedAttempts = 0; do { @@ -51,6 +53,16 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { } while (failedAttempts <= numOfRetries); } + private Long calc() { + long waitTime = waitTimeInMs; + for (int failedAttempts = 0; failedAttempts < numOfRetries; failedAttempts++) { + // 更新等待时间 + waitTime *= waitIncreaseFactor; + } + // 返回最后一次等待时间(注意:这可能不是最终你想要的逻辑,取决于你的具体需求) + return waitTime; + } + private void waitBeforeRetry(long waitTime) { try { Thread.sleep(waitTime); From fbdd24e8eaa93718f93919a9552cd34866930168 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 10:30:53 +0800 Subject: [PATCH 133/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=B9=BF=E6=92=AD=E6=B6=88=E6=81=AF=E5=9F=BA=E4=BA=8E?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E5=A4=84=E7=90=86=E7=AD=96=E7=95=A5=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=EF=BC=8C=E5=92=8C=E5=BC=82=E5=B8=B8=E7=9A=84?= =?UTF-8?q?=E6=8A=9B=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/execute/interceptor/FailOverInterceptor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index b4d2cb1ec..342640fba 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -35,7 +35,7 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { int failedAttempts = 0; do { if (failedAttempts > 0) { - log.info("Waiting for {} ms before retrying the command.", waitTime); + log.info("Waiting for {} ms before retrying the command. retryTimes: {}", waitTime, failedAttempts); waitBeforeRetry(waitTime); waitTime *= waitIncreaseFactor; } @@ -45,8 +45,7 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { } catch (Exception e) { if (failedAttempts == numOfRetries) { log.error("Workflow Engine Starter caught exception: {}", e.getMessage(), e); - } else { - log.warn("Workflow Engine Starter caught exception: {}", e.getMessage(), e); + throw e; } } failedAttempts++; From 069f11a713c453f696073a666ac58e5e1776a545 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 10:54:38 +0800 Subject: [PATCH 134/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=B9=BF=E6=92=AD=E6=B6=88=E6=81=AF=E7=9A=84=20Bean?= =?UTF-8?q?=20=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=86=8C=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8A=E5=94=AF=E4=B8=80=E5=8C=96=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/StarterBroadcastMQConfiguration.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index f79528a62..98b8f4ea5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -54,16 +54,16 @@ public class StarterBroadcastMQConfiguration { //================================= Workflow Engine Broadcast MQ =================================// @Bean - @ConditionalOnMissingBean(EventHandlerRepository.class) - public EventHandlerRepository eventHandlerRepository() { + @ConditionalOnMissingBean(value = EventHandlerRepository.class, name = "broadcastEventHandlerRepository") + public EventHandlerRepository broadcastEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { log.warn("Workflow Engine Starter MQ, handle warning {}", logText, ex); }); } @Bean - @ConditionalOnMissingBean(EventProducer.class) - public EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) { + @ConditionalOnMissingBean(value = EventProducer.class, name = "broadcastEventConsumer") + public EventConsumer broadcastEventConsumer(@Qualifier("broadcastEventHandlerRepository") EventHandlerRepository eventHandlerRepository) { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. @@ -116,7 +116,7 @@ public class StarterBroadcastMQConfiguration { } @Bean - public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("eventConsumer") EventConsumer eventConsumer, + public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("broadcastEventConsumer") EventConsumer eventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List listenerProvider) { return new WorkflowEngineBroadcastEventListener(eventConsumer, workflowEngineStarterProperties, listenerProvider); From 80bceaa1baafdf2848ec49ecfc9a11125efac93a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 10:59:54 +0800 Subject: [PATCH 135/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=B9=BF=E6=92=AD=E6=B6=88=E6=81=AF=E7=9A=84=20Bean?= =?UTF-8?q?=20=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=86=8C=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8A=E5=94=AF=E4=B8=80=E5=8C=96=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/StarterBroadcastMQConfiguration.java | 6 +++--- .../starter/StarterRPCInvokeMQConfiguration.java | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 98b8f4ea5..4dabce3f0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -53,7 +53,7 @@ public class StarterBroadcastMQConfiguration { private String activeProfile; //================================= Workflow Engine Broadcast MQ =================================// - @Bean + @Bean("broadcastEventHandlerRepository") @ConditionalOnMissingBean(value = EventHandlerRepository.class, name = "broadcastEventHandlerRepository") public EventHandlerRepository broadcastEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { @@ -61,7 +61,7 @@ public class StarterBroadcastMQConfiguration { }); } - @Bean + @Bean("broadcastEventConsumer") @ConditionalOnMissingBean(value = EventProducer.class, name = "broadcastEventConsumer") public EventConsumer broadcastEventConsumer(@Qualifier("broadcastEventHandlerRepository") EventHandlerRepository eventHandlerRepository) { Consumer callback = eventWrapper -> { @@ -115,7 +115,7 @@ public class StarterBroadcastMQConfiguration { } } - @Bean + @Bean("workflowEngineBroadcastEventListener") public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("broadcastEventConsumer") EventConsumer eventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List listenerProvider) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 3074042c9..fa052f4cd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -68,7 +68,7 @@ public class StarterRPCInvokeMQConfiguration { * @param rocketMQTemplate * @return */ - @Bean + @Bean("workflowEngineStarterEventProducer") public EventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { return new RpcInvokeEventProducer(rocketMQTemplate, DEFAULT_MODULE, @@ -133,8 +133,8 @@ public class StarterRPCInvokeMQConfiguration { }; } - @Bean - @ConditionalOnMissingBean(name = "workflowEngineStarterEventHandlerRepository") + @Bean("workflowEngineStarterEventHandlerRepository") + @ConditionalOnMissingBean(value = EventHandlerRepository.class, name = "workflowEngineStarterEventHandlerRepository") public EventHandlerRepository workflowEngineStarterEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { log.warn("MQ event handle repository has exception record: {}", logText, ex); @@ -144,8 +144,8 @@ public class StarterRPCInvokeMQConfiguration { }); } - @Bean - @ConditionalOnMissingBean(name = "workflowEngineStarterEventConsumer") + @Bean("workflowEngineStarterEventConsumer") + @ConditionalOnMissingBean(value = EventConsumer.class, name = "workflowEngineStarterEventConsumer") public EventConsumer workflowEngineStarterEventConsumer(@Qualifier("workflowEngineStarterEventHandlerRepository") EventHandlerRepository workflowEngineStarterEventHandlerRepository) { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { @@ -192,7 +192,7 @@ public class StarterRPCInvokeMQConfiguration { } } - @Bean + @Bean("workflowEngineClientRetryEventListener") public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier("workflowEngineStarterEventConsumer") EventConsumer workflowEngineStarterEventConsumer, Environment environment, WorkflowEngineStarterProperties starterProperties, From b0a4c73d077c2d51a060c6d5065b1484a7fcac84 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 11:04:37 +0800 Subject: [PATCH 136/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=B9=BF=E6=92=AD=E6=B6=88=E6=81=AF=E7=9A=84=20Bean?= =?UTF-8?q?=20=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=86=8C=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8A=E5=94=AF=E4=B8=80=E5=8C=96=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/StarterBroadcastMQConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 4dabce3f0..8ea71b547 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -85,7 +85,7 @@ public class StarterBroadcastMQConfiguration { public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); - @Resource(name = "eventConsumer") + @Resource(name = "broadcastEventConsumer") private EventConsumer eventConsumer; @Value("${spring.application.name}") private String applicationName; From 5418f8bfbb513af6dcd32c55f96684f927974632 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 13:36:55 +0800 Subject: [PATCH 137/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=B0=86=20Star?= =?UTF-8?q?ter=20=E4=B8=AD=E5=86=85=E7=BD=AE=20Bean=20=E7=9A=84=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E9=9D=99=E6=80=81=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StarterBroadcastMQConfiguration.java | 30 ++++++++++--------- .../StarterRPCInvokeMQConfiguration.java | 20 +++++++------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 8ea71b547..7f55753b3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -5,11 +5,10 @@ import cn.axzo.framework.rocketmq.DefaultEventConsumer; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; -import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; import cn.axzo.workflow.starter.handler.filter.global.BroadcastMessageQueueFilter; -import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; +import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterDefinitionKey; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterExtension; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; @@ -46,24 +45,27 @@ import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_E @Configuration(proxyBeanMethods = false) public class StarterBroadcastMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterBroadcastMQConfiguration.class); - + public static final String BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME = "broadcastEventHandlerRepository"; + public static final String BROADCAST_EVENT_CONSUMER_BEAN_NAME = "broadcastEventConsumer"; @Value("${spring.application.name}") private String applicationName; @Value("${spring.profiles.active:dev}") private String activeProfile; //================================= Workflow Engine Broadcast MQ =================================// - @Bean("broadcastEventHandlerRepository") - @ConditionalOnMissingBean(value = EventHandlerRepository.class, name = "broadcastEventHandlerRepository") + @Bean(BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) + @ConditionalOnMissingBean(name = BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) public EventHandlerRepository broadcastEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { - log.warn("Workflow Engine Starter MQ, handle warning {}", logText, ex); + // 不管 cn.axzo.workflow.starter.BroadcastListenerProperties.failHandleType 设置是哪种策略,这里最终都会打印 WARN 级别日志,框架底层会对所有异常的消息打印 ERROR 日志 + // 如果不想打印需要扩展内部逻辑,请主动注册自己扩展的 Bean,且名称为 StarterBroadcastMQConfiguration.BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME + log.warn("Workflow Engine Starter MQ, an exception occurred during processing {}", logText, ex); }); } - @Bean("broadcastEventConsumer") - @ConditionalOnMissingBean(value = EventProducer.class, name = "broadcastEventConsumer") - public EventConsumer broadcastEventConsumer(@Qualifier("broadcastEventHandlerRepository") EventHandlerRepository eventHandlerRepository) { + @Bean(BROADCAST_EVENT_CONSUMER_BEAN_NAME) + @ConditionalOnMissingBean(name = BROADCAST_EVENT_CONSUMER_BEAN_NAME) + public EventConsumer broadcastEventConsumer(@Qualifier(BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) EventHandlerRepository eventHandlerRepository) { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. @@ -85,8 +87,8 @@ public class StarterBroadcastMQConfiguration { public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); - @Resource(name = "broadcastEventConsumer") - private EventConsumer eventConsumer; + @Resource(name = BROADCAST_EVENT_CONSUMER_BEAN_NAME) + private EventConsumer broadcastEventConsumer; @Value("${spring.application.name}") private String applicationName; @Resource @@ -103,7 +105,7 @@ public class StarterBroadcastMQConfiguration { return; } } - super.onEvent(message, eventConsumer); + super.onEvent(message, broadcastEventConsumer); } @Override @@ -116,9 +118,9 @@ public class StarterBroadcastMQConfiguration { } @Bean("workflowEngineBroadcastEventListener") - public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier("broadcastEventConsumer") EventConsumer eventConsumer, + public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier(BROADCAST_EVENT_CONSUMER_BEAN_NAME) EventConsumer broadcastEventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List listenerProvider) { - return new WorkflowEngineBroadcastEventListener(eventConsumer, workflowEngineStarterProperties, listenerProvider); + return new WorkflowEngineBroadcastEventListener(broadcastEventConsumer, workflowEngineStarterProperties, listenerProvider); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index fa052f4cd..2a291e8bc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -50,7 +50,9 @@ import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; @Configuration(proxyBeanMethods = false) public class StarterRPCInvokeMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterRPCInvokeMQConfiguration.class); - + public static final String WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME = "workflowEngineStarterEventProducer"; + public static final String WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME = "workflowEngineStarterEventConsumer"; + public static final String WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME = "workflowEngineStarterEventHandlerRepository"; public static final String DEFAULT_MODULE = "workflowEngine"; public static final String DEFAULT_EVENT = "topic_workflow_engine_"; private static final String MODULE_NAME_SUFFIX = "_rpc_retry_starter"; @@ -68,7 +70,7 @@ public class StarterRPCInvokeMQConfiguration { * @param rocketMQTemplate * @return */ - @Bean("workflowEngineStarterEventProducer") + @Bean(WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME) public EventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { return new RpcInvokeEventProducer(rocketMQTemplate, DEFAULT_MODULE, @@ -133,8 +135,8 @@ public class StarterRPCInvokeMQConfiguration { }; } - @Bean("workflowEngineStarterEventHandlerRepository") - @ConditionalOnMissingBean(value = EventHandlerRepository.class, name = "workflowEngineStarterEventHandlerRepository") + @Bean(WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) + @ConditionalOnMissingBean(name = WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) public EventHandlerRepository workflowEngineStarterEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { log.warn("MQ event handle repository has exception record: {}", logText, ex); @@ -144,9 +146,9 @@ public class StarterRPCInvokeMQConfiguration { }); } - @Bean("workflowEngineStarterEventConsumer") - @ConditionalOnMissingBean(value = EventConsumer.class, name = "workflowEngineStarterEventConsumer") - public EventConsumer workflowEngineStarterEventConsumer(@Qualifier("workflowEngineStarterEventHandlerRepository") EventHandlerRepository workflowEngineStarterEventHandlerRepository) { + @Bean(WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) + @ConditionalOnMissingBean(name = WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) + public EventConsumer workflowEngineStarterEventConsumer(@Qualifier(WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) EventHandlerRepository workflowEngineStarterEventHandlerRepository) { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. @@ -169,7 +171,7 @@ public class StarterRPCInvokeMQConfiguration { public static class WorkflowEngineStarterRetryConsumer extends BaseListener implements RocketMQListener, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterRetryConsumer.class); - @Resource(name = "workflowEngineStarterEventConsumer") + @Resource(name = WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) private EventConsumer workflowEngineStarterEventConsumer; @Value("${spring.application.name}") private String applicationName; @@ -193,7 +195,7 @@ public class StarterRPCInvokeMQConfiguration { } @Bean("workflowEngineClientRetryEventListener") - public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier("workflowEngineStarterEventConsumer") EventConsumer workflowEngineStarterEventConsumer, + public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier(WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) EventConsumer workflowEngineStarterEventConsumer, Environment environment, WorkflowEngineStarterProperties starterProperties, ObjectProvider workflowCoreServiceObjectProvider, From 844990df3f4b6997511db59960eaab0249708fa9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 13:37:05 +0800 Subject: [PATCH 138/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=B8=80=E4=BA=9B=E5=BC=82=E5=B8=B8=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/WorkflowNoMethodException.java | 17 +++++++++++++++++ ...WorkflowEngineStarterRetryEventListener.java | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowNoMethodException.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowNoMethodException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowNoMethodException.java new file mode 100644 index 000000000..b4a7ffba8 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowNoMethodException.java @@ -0,0 +1,17 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * 特殊的 invoke 逻辑中,没有特定的方法异常 + * + * @author wangli + * @since 2024/6/14 13:35 + */ +public class WorkflowNoMethodException extends WorkflowEngineStarterException { + public WorkflowNoMethodException(String message) { + super(message); + } + + public WorkflowNoMethodException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index 5b0983366..a73719d3c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -9,6 +9,7 @@ import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.api.WorkflowManageService; +import cn.axzo.workflow.starter.common.exception.WorkflowNoMethodException; import com.alibaba.fastjson.JSON; import lombok.SneakyThrows; import org.slf4j.Logger; @@ -121,7 +122,7 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In InterfaceMapping mapping = methodCache.getOrDefault(dto.getMethodName(), null); if (Objects.isNull(mapping)) { - throw new IllegalStateException("Not found method:" + dto.getMethodName()); + throw new WorkflowNoMethodException("Not method found: " + dto.getMethodName()); } try { // 事件处理 RPC 请求, 强制使用同步模式 From 75bfe6088458cd1918b8aa35eeaa08aec725c69a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 14:45:38 +0800 Subject: [PATCH 139/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=85=8B?= =?UTF-8?q?=E5=88=B6=20Starter=20=E4=B8=AD=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0=EF=BC=8C=E9=85=8D=E5=90=88=20logback=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=8C=89=E9=9C=80=E8=BF=9B=E8=A1=8C=E8=BE=93?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StarterBroadcastMQConfiguration.java | 6 ++++-- .../WorkflowEngineStarterProperties.java | 18 ++++++++++++++++++ .../NonContainerEnvironmentCondition.java | 9 +++++++-- .../execute/interceptor/LogInterceptor.java | 12 +++++++++--- .../WorkflowEngineBroadcastEventListener.java | 2 +- ...orkflowEngineStarterRetryEventListener.java | 8 ++++++-- .../retry/producer/RpcInvokeEventProducer.java | 10 +++++++--- 7 files changed, 52 insertions(+), 13 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 7f55753b3..3741d12e1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -69,8 +69,10 @@ public class StarterBroadcastMQConfiguration { Consumer callback = eventWrapper -> { if (eventWrapper.isHandled()) { // 只收集被App真正消费的消息. - Event event = eventWrapper.getEvent(); - log.info("WorkflowEngine Broadcast MQ, handled event: {}", event.toPrettyJsonString()); + if (log.isDebugEnabled()) { + Event event = eventWrapper.getEvent(); + log.debug("WorkflowEngine Broadcast MQ, handled event: {}", event.toPrettyJsonString()); + } } }; return new DefaultEventConsumer(applicationName, eventHandlerRepository, callback); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index e62efe7dd..9c9b0ab0f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -33,6 +33,16 @@ public class WorkflowEngineStarterProperties { */ private Boolean joinContainerGroup = false; + /** + *

该参数只针对容器环境生效

+ * 配合 joinContainerGroup 使用,且只在 joinContainerGroup = false 时生效 + *
+     * 在本地有多台开发机同时启动时,又会组成新的集群消费,也会导致消息异常消费,
+     * 所以该参数就是为了创建完全唯一的消费者,避免本地开发机组成集群。
+     * 
+ */ + private String specialId; + /** * WorkflowCoreService 类中所有方法未标记{@link InvokeMode}注解的方法调用时, 默认采用的模式 * @@ -68,6 +78,14 @@ public class WorkflowEngineStarterProperties { this.joinContainerGroup = joinContainerGroup; } + public String getSpecialId() { + return specialId; + } + + public void setSpecialId(String specialId) { + this.specialId = specialId; + } + public RpcInvokeModeEnum getInvokeMode() { return invokeMode; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java index 495c585b0..c942f6870 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java @@ -32,6 +32,7 @@ public class NonContainerEnvironmentCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment(); + // 依赖 K8S 设置的环境变量信息,如果变量的 key 发生变化,会导致此处的功能可能出现异常 String myPodNamespace = environment.getProperty(K8S_POD_NAME_SPACE); String activeProfile = environment.getProperty(NACOS_PROFILES_ACTIVE); if (!StringUtils.hasText(activeProfile)) { @@ -49,10 +50,14 @@ public class NonContainerEnvironmentCondition implements Condition { // 获取默认值 joinContainerGroup = new WorkflowEngineStarterProperties().getJoinContainerGroup(); } - log.debug("workflow engine starter join-container-group status: {} ", joinContainerGroup); + if (log.isDebugEnabled()) { + log.debug("workflow engine starter join-container-group status: {} ", joinContainerGroup); + } + String specialId = environment.getProperty("workflow.engine.starter.special-id", String.class); environment.getSystemProperties().put(MQ_GID_NAME_SEGMENT, - joinContainerGroup ? activeProfile : activeProfile + DEBUGGING_MQ_SUFFIX); + joinContainerGroup ? activeProfile : + activeProfile + (StringUtils.hasText(specialId) ? "_" + specialId : "") + DEBUGGING_MQ_SUFFIX); return true; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java index 7228c5fd6..665e7bf84 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java @@ -16,13 +16,19 @@ public final class LogInterceptor extends AbstractListenerInterceptor { public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); - log.debug("--- starting handle mq ---- "); - log.info("messageId: {}, eventCode: {}, messageBody: {}", context.getMsgId(), context.getEventCode().toString(), JSON.toJSONString(t)); + if (log.isDebugEnabled()) { + log.debug("--- starting handle mq ---- "); + } + if (log.isInfoEnabled()) { + log.info("messageId: {}, eventCode: {}, messageBody: {}", context.getMsgId(), context.getEventCode().toString(), JSON.toJSONString(t)); + } try { getNext().execute(executor, consumer, context, t); } finally { stopWatch.stop(); - log.debug("--- messageId: {} finished ,timeCost:{} ms ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); + if (log.isDebugEnabled()) { + log.debug("--- messageId: {} finished ,timeCost:{} ms ---", executor.getClass().getSimpleName(), stopWatch.getTotalTimeMillis()); + } } } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java index 334998221..d3c09b78b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/broadcast/consumer/WorkflowEngineBroadcastEventListener.java @@ -35,7 +35,7 @@ public class WorkflowEngineBroadcastEventListener implements EventHandler, Initi @Override public void onEvent(Event event, EventConsumer.Context context) { if (Objects.isNull(event) || Objects.isNull(event.getEventCode())) { - log.warn("illegal event code: {}", event); + log.warn("illegal event code: {}", JSON.toJSONString(event)); return; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java index a73719d3c..0b847c0d0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/consumer/WorkflowEngineStarterRetryEventListener.java @@ -128,9 +128,13 @@ public class WorkflowEngineStarterRetryEventListener implements EventHandler, In // 事件处理 RPC 请求, 强制使用同步模式 ThreadUtil.set(SYNC); Object[] args = convertToActualArgs(mapping.getMethod(), dto.getParameters()); - log.debug("event rpc request args: {}", JSON.toJSONString(args)); + if (log.isDebugEnabled()) { + log.debug("event rpc request args: {}", JSON.toJSONString(args)); + } Object invoke = mapping.getMethod().invoke(mapping.getInterfaceObject(), args); - log.debug("Event Invoke Result: {}", JSON.toJSONString(invoke)); + if (log.isDebugEnabled()) { + log.debug("Event Invoke Result: {}", JSON.toJSONString(invoke)); + } } catch (Throwable e) { // 能抛出异常目前只有两种情况, 一个是网络异常, 另一个是对端服务内部异常 Throwable cause = getRealCause(e); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java index b61406bef..de7f2fc80 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/retry/producer/RpcInvokeEventProducer.java @@ -49,7 +49,9 @@ public class RpcInvokeEventProducer extends RocketMQEventProducer { @Override public void send(@NonNull Event event, @NonNull Context context) { - log.info("发送事件内容: {}", event.toPrettyJsonString()); + if (log.isDebugEnabled()) { + log.debug("发送事件内容: {}", event.toPrettyJsonString()); + } if (sendBeforeCallback != null) { sendBeforeCallback.accept(event, context); } @@ -101,8 +103,10 @@ public class RpcInvokeEventProducer extends RocketMQEventProducer { getAfterCommitExecutor().executeAndRollback(runnable, rollbackRunnable); } - List runnables = ListUtils.emptyIfNull(getAfterCommitExecutor().getRunnables()); - log.info("runnables.size(): {}", runnables.size()); + if (log.isDebugEnabled()) { + List runnables = ListUtils.emptyIfNull(getAfterCommitExecutor().getRunnables()); + log.debug("runnables.size(): {}", runnables.size()); + } } @Override From 1710356e31fcc7e332dcf938a194068a85ee5261 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 14:52:13 +0800 Subject: [PATCH 140/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=BE=9B=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/handler/MessageNotificationEventHandler.java | 2 ++ .../workflow/starter/handler/ProcessActivityEventHandler.java | 2 ++ .../workflow/starter/handler/ProcessInstanceEventHandler.java | 2 ++ .../axzo/workflow/starter/handler/ProcessTaskEventHandler.java | 2 ++ .../starter/handler/filter/MessageNotificationEventFilter.java | 2 ++ .../starter/handler/filter/ProcessActivityEventFilter.java | 2 ++ .../starter/handler/filter/ProcessInstanceEventFilter.java | 2 ++ .../workflow/starter/handler/filter/ProcessTaskEventFilter.java | 2 ++ 8 files changed, 16 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java index 5230cb6c8..d07200a38 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/MessageNotificationEventHandler.java @@ -5,6 +5,8 @@ import org.springframework.core.Ordered; /** * 引擎广播发送消息的事件, 业务一般无需实现,该事件由引擎的中继服务去处理待办相关动作的。 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/5/27 16:25 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java index fa568e4e0..eeb3c2724 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessActivityEventHandler.java @@ -10,6 +10,8 @@ import org.springframework.core.Ordered; *

  *  OMS -> 审批流程 -> 审批配置台 -> 流程配置
  * 
+ *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/5/27 16:25 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java index 96748a320..f427ac927 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessInstanceEventHandler.java @@ -7,6 +7,8 @@ import org.springframework.core.Ordered; /** * 流程实例相关事件 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/5/27 16:20 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java index 700548219..abb3d896c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/ProcessTaskEventHandler.java @@ -7,6 +7,8 @@ import org.springframework.core.Ordered; * 审批任务相关事件 *

* 一个节点(Activity)可以包含 0个或多个任务(Task),它们两者是包含关系 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/5/27 16:21 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java index d7de82061..aa184f8ed 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/MessageNotificationEventFilter.java @@ -5,6 +5,8 @@ import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; /** * MessageNotificationEvent 的自定义过滤接口 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/6/5 15:49 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java index a79f2b539..a769d28b3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessActivityEventFilter.java @@ -5,6 +5,8 @@ import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; /** * ProcessActivityEvent 自定义的过滤接口 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/6/5 15:49 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java index 91ab141d7..fb04e3360 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessInstanceEventFilter.java @@ -5,6 +5,8 @@ import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; /** * ProcessInstanceEvent 自定义的过滤接口 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/6/5 15:44 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java index afd16f414..22ac91008 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/filter/ProcessTaskEventFilter.java @@ -5,6 +5,8 @@ import cn.axzo.workflow.starter.mq.broadcast.filter.BasicMessageQueueFilter; /** * ProcessTaskEvent 自定义的过滤接口 + *

+ * 注意:Order 的顺序,遵循值越小越优先。(取值范围:Integer. MIN_VALUE - Integer. MAX_VALUE) * * @author wangli * @since 2024/6/5 15:50 From c9542394c1f9c34ec6a1da172c03cb32914c49e0 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 15:08:59 +0800 Subject: [PATCH 141/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E7=94=9F=E6=88=90=E4=BB=A3=E7=A0=81=E7=9A=84=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-support/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-support/pom.xml b/workflow-engine-support/pom.xml index 25007a6f7..1c04d54f7 100644 --- a/workflow-engine-support/pom.xml +++ b/workflow-engine-support/pom.xml @@ -21,7 +21,7 @@ org.codehaus.mojo exec-maven-plugin - 3.3.0 + 3.1.0 run-custom-code From 2659a95d53eb15627e9ae051c2813a411771c63b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 15:33:20 +0800 Subject: [PATCH 142/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dmq=20=E7=9B=91=E6=8E=A7=E5=8A=9F=E8=83=BD=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E8=BF=87=E7=A8=8B=E6=9C=AA=E6=AD=A3=E7=A1=AE=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E5=88=B0nameServer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 11 ++++--- ...WorkflowEngineStarterDefaultMQMonitor.java | 9 ++++-- ...kflowEngineStarterMQMonitorController.java | 30 ++++++++++--------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 4b6982e5c..feecbf47a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -31,6 +31,7 @@ import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -39,6 +40,7 @@ import org.springframework.core.env.Environment; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Workflow Engine Auto Configuration @@ -112,8 +114,9 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean(destroyMethod = "shutdown", name = "defaultMQAdminExt") - public DefaultMQAdminExt defaultMQAdminExt() { - String namesrvAddress = System.getProperty("rocketmq.name-server"); + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") + public DefaultMQAdminExt defaultMQAdminExt(Environment environment) { + String namesrvAddress = environment.getProperty("rocketmq.name-server"); if (StringUtils.isBlank(namesrvAddress)) { log.error("Build DefaultMQAdminExt error, namesrv is null"); throw new RuntimeException("Build DefaultMQAdminExt error, namesrv is null", null); @@ -135,8 +138,8 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean - public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt, + public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, Environment environment) { - return new WorkflowEngineStarterDefaultMQMonitor(defaultMQAdminExt, environment); + return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, environment); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index d45561213..8982a7c47 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -1,10 +1,10 @@ package cn.axzo.workflow.starter.mq.monitor; -import lombok.SneakyThrows; import org.apache.rocketmq.common.admin.ConsumeStats; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.SmartLifecycle; import org.springframework.core.env.Environment; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @@ -25,6 +25,9 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_N public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private static final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterDefaultMQMonitor.class); + /** + * 可能为 null + */ private final DefaultMQAdminExt defaultMQAdminExt; private final Environment environment; private final ThreadPoolTaskScheduler taskScheduler; @@ -33,8 +36,8 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private ConsumeStats rpcConsumeStats; private final Map messageQueue = new HashMap<>(); - public WorkflowEngineStarterDefaultMQMonitor(DefaultMQAdminExt defaultMQAdminExt, Environment environment) { - this.defaultMQAdminExt = defaultMQAdminExt; + public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, Environment environment) { + this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; this.taskScheduler = init(); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index b1367687b..be3ac08e6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -2,8 +2,8 @@ package cn.axzo.workflow.starter.mq.monitor.console; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.azxo.framework.common.model.CommonResponse; -import lombok.SneakyThrows; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.GetMapping; @@ -29,7 +29,7 @@ public class WorkflowEngineStarterMQMonitorController { @Resource private WorkflowEngineStarterProperties starterProperties; @Resource - private DefaultMQAdminExt defaultMQAdminExt; + private ObjectProvider mqAdminExtObjectProvider; @Resource private Environment environment; @Value("${spring.application.name}") @@ -40,21 +40,23 @@ public class WorkflowEngineStarterMQMonitorController { public static String RPC_RETRY_CONSUMER_GROUP = "GID_%s_workflow_engine_starter_%s_consumer"; @GetMapping("/m") - public CommonResponse> monitor() throws Exception { + public CommonResponse> monitor() { String topic = DEFAULT_EVENT + activeProfile; Map result = new HashMap<>(); + mqAdminExtObjectProvider.ifAvailable(defaultMQAdminExt -> { + String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); + try { + result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment))); + result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment))); - String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); - result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment))); - result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment))); - - result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); - result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); - result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); - result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); - - - + result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); + result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); + result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); + result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); + } catch (Exception e) { + e.printStackTrace(); + } + }); return CommonResponse.success(result); } } From 476ea553223cb690f1ac3a6cf555e1f1d3f2411b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 16:32:42 +0800 Subject: [PATCH 143/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=20MQ=20=E6=AD=BB=E4=BF=A1=E9=98=9F=E5=88=97=E7=9A=84?= =?UTF-8?q?=E7=9B=91=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...WorkflowEngineStarterDefaultMQMonitor.java | 75 +++++++++---------- ...kflowEngineStarterMQMonitorController.java | 20 +++-- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 8982a7c47..26293118c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.starter.mq.monitor; +import lombok.SneakyThrows; import org.apache.rocketmq.common.admin.ConsumeStats; +import org.apache.rocketmq.common.admin.TopicStatsTable; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,6 +10,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.SmartLifecycle; import org.springframework.core.env.Environment; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.util.CollectionUtils; import java.util.HashMap; import java.util.Map; @@ -15,6 +18,8 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.BROADCAST_CONSUMER_GROUP; +import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.RPC_RETRY_CONSUMER_GROUP; /** * 用于监控 Starter 关注的 Topic 相关的 Producer 与 Consumer 信息 @@ -25,6 +30,7 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_N public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private static final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterDefaultMQMonitor.class); + public static final String DLQ_PREFIX = "%DLQ%"; /** * 可能为 null */ @@ -32,9 +38,6 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private final Environment environment; private final ThreadPoolTaskScheduler taskScheduler; private final AtomicBoolean running = new AtomicBoolean(false); - private ConsumeStats broadcastConsumeStats; - private ConsumeStats rpcConsumeStats; - private final Map messageQueue = new HashMap<>(); public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, Environment environment) { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); @@ -49,51 +52,49 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { return taskScheduler; } + @SneakyThrows public void mqWatch() { - log.debug("time is :{}", System.currentTimeMillis()); String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); String applicationName = environment.getProperty("spring.application.name"); // 周期性比对 -// compareBroadcast(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment)); -// compareRPC(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment)); + compareBroadcastDLQ(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment)); + compareRPCDLQ(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment)); } - private void compareRPC(String consumerGroupName) throws Exception { + private void compareRPCDLQ(String consumerGroupName) throws Exception { log.info("current rpc consumer group is :{}", consumerGroupName); - ConsumeStats consumeStats = defaultMQAdminExt.examineConsumeStats(consumerGroupName); - if (Objects.isNull(broadcastConsumeStats)) { - broadcastConsumeStats = consumeStats; - messageQueue.putAll(calcCurrentTimes(consumerGroupName, consumeStats)); - return; - } - Map temp = calcCurrentTimes(consumerGroupName, consumeStats); - } - - private static Map calcCurrentTimes(String consumerGroupName, ConsumeStats consumeStats) { - Map temp = new HashMap<>(); - String rpcDeadLetterConsumerName = "%RETRY%" + consumerGroupName; - consumeStats.getOffsetTable().forEach((k, v) -> { - long l = v.getBrokerOffset() - v.getConsumerOffset(); - if (Objects.equals(k.getTopic(), rpcDeadLetterConsumerName)) { - // 死信队列 - temp.put(rpcDeadLetterConsumerName, l); - } else { - // 普通队列 - temp.computeIfPresent(consumerGroupName, ((k1, v1) -> v1 + l)); + try { + TopicStatsTable table = defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + consumerGroupName); + if (Objects.isNull(table) || CollectionUtils.isEmpty(table.getOffsetTable())) { + return; } - }); - return temp; + table.getOffsetTable().forEach((k, v) -> { + if (Objects.equals(DLQ_PREFIX + consumerGroupName, k.getTopic())) { + long dlqCount = v.getMaxOffset() - v.getMinOffset(); + log.error("found rpc MQ DLQ, count: {}", dlqCount); + } + }); + } catch (Exception e) { + log.warn("monitor RPC DLQ error: {}", e.getMessage(), e); + } } - private void compareBroadcast(String consumerGroupName) throws Exception { + private void compareBroadcastDLQ(String consumerGroupName) throws Exception { log.info("current broadcast consumer group is :{}", consumerGroupName); - ConsumeStats consumeStats = defaultMQAdminExt.examineConsumeStats(consumerGroupName); - if (Objects.isNull(rpcConsumeStats)) { - rpcConsumeStats = consumeStats; - messageQueue.putAll(calcCurrentTimes(consumerGroupName, consumeStats)); - return; + try { + TopicStatsTable table = defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + consumerGroupName); + if (Objects.isNull(table) || CollectionUtils.isEmpty(table.getOffsetTable())) { + return; + } + table.getOffsetTable().forEach((k, v) -> { + if (Objects.equals(DLQ_PREFIX + consumerGroupName, k.getTopic())) { + long dlqCount = v.getMaxOffset() - v.getMinOffset(); + log.error("found Broadcast MQ DLQ, count: {}", dlqCount); + } + }); + } catch (Exception e) { + log.warn("monitor Broadcast DLQ error: {}", e.getMessage(), e); } - Map temp = calcCurrentTimes(consumerGroupName, consumeStats); } @Override @@ -109,8 +110,6 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { if (running.compareAndSet(true, false)) { log.info("destroying workflow engine mq monitor"); taskScheduler.shutdown(); - broadcastConsumeStats = null; - rpcConsumeStats = null; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index be3ac08e6..2f1ce8c71 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -3,6 +3,8 @@ package cn.axzo.workflow.starter.mq.monitor.console; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.azxo.framework.common.model.CommonResponse; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; @@ -16,6 +18,7 @@ import java.util.Map; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor.DLQ_PREFIX; /** * Workflow Engine Starter MessageQueue Monitor Controller @@ -26,6 +29,7 @@ import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_N @RestController @RequestMapping("/web/we/s") public class WorkflowEngineStarterMQMonitorController { + private static final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterMQMonitorController.class); @Resource private WorkflowEngineStarterProperties starterProperties; @Resource @@ -46,15 +50,19 @@ public class WorkflowEngineStarterMQMonitorController { mqAdminExtObjectProvider.ifAvailable(defaultMQAdminExt -> { String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); try { - result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment))); - result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment))); + String broadcastConsumer = String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment); + String rpcConsumer = String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment); + result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(broadcastConsumer)); + result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(rpcConsumer)); - result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); - result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); +// result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); +// result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); - result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); +// result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); + result.put("广播-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + broadcastConsumer)); + result.put("RPC-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + rpcConsumer)); } catch (Exception e) { - e.printStackTrace(); + log.warn("monitor controller error: {}", e.getMessage(), e); } }); return CommonResponse.success(result); From ebef19a9d52a04c9ebd30fd6448cdc0598b3deed Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 17:37:46 +0800 Subject: [PATCH 144/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20MQ=20=E7=9B=91=E6=8E=A7=E7=9A=84=EF=BC=8C=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E6=AD=BB=E4=BF=A1=E9=98=9F=E5=88=97=E7=9A=84=E9=92=A9?= =?UTF-8?q?=E5=AD=90=EF=BC=8C=E5=90=8C=E6=97=B6=EF=BC=8C=E4=B9=9F=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8F=AF=E5=8A=A8=E6=80=81=E5=BC=80=E5=85=B3=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E7=9A=84=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...orkflowEngineStarterAutoConfiguration.java | 9 ++- .../WorkflowEngineStarterProperties.java | 25 ++++++++ .../monitor/BroadcastDLQProcessor.java | 24 ++++++++ .../handler/monitor/RpcDLQProcessor.java | 25 ++++++++ ...WorkflowEngineStarterDefaultMQMonitor.java | 46 +++++++-------- ...kflowEngineStarterMQMonitorController.java | 57 ++++++++++++++----- 6 files changed, 145 insertions(+), 41 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index feecbf47a..de11113cc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -16,6 +16,8 @@ import cn.axzo.workflow.starter.handler.filter.MessageNotificationEventFilter; import cn.axzo.workflow.starter.handler.filter.ProcessActivityEventFilter; import cn.axzo.workflow.starter.handler.filter.ProcessInstanceEventFilter; import cn.axzo.workflow.starter.handler.filter.ProcessTaskEventFilter; +import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQProcessor; +import cn.axzo.workflow.starter.handler.monitor.RpcDLQProcessor; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; @@ -114,7 +116,7 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean(destroyMethod = "shutdown", name = "defaultMQAdminExt") - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true") public DefaultMQAdminExt defaultMQAdminExt(Environment environment) { String namesrvAddress = environment.getProperty("rocketmq.name-server"); if (StringUtils.isBlank(namesrvAddress)) { @@ -138,8 +140,11 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true") public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, + ObjectProvider broadcastDLQProcessorObjectProvider, + ObjectProvider rpcDLQProcessorObjectProvider, Environment environment) { - return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, environment); + return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, broadcastDLQProcessorObjectProvider, rpcDLQProcessorObjectProvider, environment); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 9c9b0ab0f..86da8f41d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -62,6 +62,15 @@ public class WorkflowEngineStarterProperties { @NestedConfigurationProperty private BroadcastListenerProperties broadcast = new BroadcastListenerProperties(); + /** + * 是否开始死信队列的监控 + */ + private Boolean enableDlqMonitor = false; + /** + * 监控死信队列,周期间隔,单位:毫秒 + */ + private Long DlqMonitorIntervalInMs = 4 * 60 * 60 * 1000L; + public Boolean getManageable() { return manageable; } @@ -101,4 +110,20 @@ public class WorkflowEngineStarterProperties { public void setBroadcast(BroadcastListenerProperties broadcast) { this.broadcast = broadcast; } + + public Boolean getEnableDlqMonitor() { + return enableDlqMonitor; + } + + public void setEnableDlqMonitor(Boolean enableDlqMonitor) { + this.enableDlqMonitor = enableDlqMonitor; + } + + public Long getDlqMonitorIntervalInMs() { + return DlqMonitorIntervalInMs; + } + + public void setDlqMonitorIntervalInMs(Long dlqMonitorIntervalInMs) { + DlqMonitorIntervalInMs = dlqMonitorIntervalInMs; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java new file mode 100644 index 000000000..3edc50ea1 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java @@ -0,0 +1,24 @@ +package cn.axzo.workflow.starter.handler.monitor; + +import org.apache.rocketmq.common.admin.TopicOffset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 广播死信队列监控的处理器, 默认仅仅是打印异常。 + *

+ * 可以用它来发生钉钉之类的。 + *

+ * 注意:该接口目前不是为了消费死信队列中的消息的。后续必要时,再开放死信队列的消费扩展点 + * + * @author wangli + * @since 2024/6/14 17:04 + */ +public interface BroadcastDLQProcessor { + Logger log = LoggerFactory.getLogger(BroadcastDLQProcessor.class); + + default void process(TopicOffset v) { + long dlqCount = v.getMaxOffset() - v.getMinOffset(); + log.error("found Broadcast MQ DLQ, count: {}", dlqCount); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java new file mode 100644 index 000000000..6aeaa49f7 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.starter.handler.monitor; + +import org.apache.rocketmq.common.admin.TopicOffset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * RPC 重试的死信队列监控处理器, 默认仅仅是打印异常 + *

+ * 可以用它来发生钉钉之类的. + *

+ * 注意:该接口目前不是为了消费死信队列中的消息的。后续必要时,再开放死信队列的消费扩展点 + * + * @author wangli + * @since 2024/6/14 17:01 + */ + +public interface RpcDLQProcessor { + Logger log = LoggerFactory.getLogger(RpcDLQProcessor.class); + + default void process(TopicOffset v) { + long dlqCount = v.getMaxOffset() - v.getMinOffset(); + log.error("found rpc MQ DLQ, count: {}", dlqCount); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 26293118c..bda4ea56c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -1,7 +1,8 @@ package cn.axzo.workflow.starter.mq.monitor; +import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQProcessor; +import cn.axzo.workflow.starter.handler.monitor.RpcDLQProcessor; import lombok.SneakyThrows; -import org.apache.rocketmq.common.admin.ConsumeStats; import org.apache.rocketmq.common.admin.TopicStatsTable; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; @@ -16,6 +17,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.BROADCAST_CONSUMER_GROUP; @@ -37,11 +39,20 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private final DefaultMQAdminExt defaultMQAdminExt; private final Environment environment; private final ThreadPoolTaskScheduler taskScheduler; + private final BroadcastDLQProcessor broadcastDLQProcessor; + private final RpcDLQProcessor rpcDLQProcessor; private final AtomicBoolean running = new AtomicBoolean(false); + private final Map> dlqProcessCache = new HashMap<>(); - public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, Environment environment) { + public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, + ObjectProvider broadcastDLQProcessorObjectProvider, + ObjectProvider rpcDLQProcessorObjectProvider, Environment environment) { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; + this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQProcessor() { + }); + this.rpcDLQProcessor = rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQProcessor() { + }); this.taskScheduler = init(); } @@ -57,29 +68,11 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); String applicationName = environment.getProperty("spring.application.name"); // 周期性比对 - compareBroadcastDLQ(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment)); - compareRPCDLQ(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment)); + compareDLQ(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment), "broadcast"); + compareDLQ(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment), "rpc"); } - private void compareRPCDLQ(String consumerGroupName) throws Exception { - log.info("current rpc consumer group is :{}", consumerGroupName); - try { - TopicStatsTable table = defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + consumerGroupName); - if (Objects.isNull(table) || CollectionUtils.isEmpty(table.getOffsetTable())) { - return; - } - table.getOffsetTable().forEach((k, v) -> { - if (Objects.equals(DLQ_PREFIX + consumerGroupName, k.getTopic())) { - long dlqCount = v.getMaxOffset() - v.getMinOffset(); - log.error("found rpc MQ DLQ, count: {}", dlqCount); - } - }); - } catch (Exception e) { - log.warn("monitor RPC DLQ error: {}", e.getMessage(), e); - } - } - - private void compareBroadcastDLQ(String consumerGroupName) throws Exception { + private void compareDLQ(String consumerGroupName, String dqlType) throws Exception { log.info("current broadcast consumer group is :{}", consumerGroupName); try { TopicStatsTable table = defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + consumerGroupName); @@ -88,8 +81,11 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { } table.getOffsetTable().forEach((k, v) -> { if (Objects.equals(DLQ_PREFIX + consumerGroupName, k.getTopic())) { - long dlqCount = v.getMaxOffset() - v.getMinOffset(); - log.error("found Broadcast MQ DLQ, count: {}", dlqCount); + if ("broadcast".equals(dqlType)) { + broadcastDLQProcessor.process(v); + } else if ("rpc".equals(dqlType)) { + rpcDLQProcessor.process(v); + } } }); } catch (Exception e) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index 2f1ce8c71..d1689bd5d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.starter.mq.monitor.console; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; import cn.azxo.framework.common.model.CommonResponse; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; @@ -10,6 +11,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @@ -35,6 +37,8 @@ public class WorkflowEngineStarterMQMonitorController { @Resource private ObjectProvider mqAdminExtObjectProvider; @Resource + private WorkflowEngineStarterDefaultMQMonitor monitor; + @Resource private Environment environment; @Value("${spring.application.name}") private String applicationName; @@ -47,24 +51,49 @@ public class WorkflowEngineStarterMQMonitorController { public CommonResponse> monitor() { String topic = DEFAULT_EVENT + activeProfile; Map result = new HashMap<>(); - mqAdminExtObjectProvider.ifAvailable(defaultMQAdminExt -> { - String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); - try { - String broadcastConsumer = String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment); - String rpcConsumer = String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment); - result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(broadcastConsumer)); - result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(rpcConsumer)); + if (!starterProperties.getEnableDlqMonitor()) { + result.put("Info", "未开启·死信队列·的监控,如需,请设置 workflow.engine.starter.enableDlqMonitor = true 后再重试!"); + } else { + mqAdminExtObjectProvider.ifAvailable(defaultMQAdminExt -> { + String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); + try { + String broadcastConsumer = String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment); + String rpcConsumer = String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment); + result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(broadcastConsumer)); + result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(rpcConsumer)); // result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); // result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); - result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); + result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); // result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); - result.put("广播-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + broadcastConsumer)); - result.put("RPC-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + rpcConsumer)); - } catch (Exception e) { - log.warn("monitor controller error: {}", e.getMessage(), e); - } - }); + result.put("Broadcast-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + broadcastConsumer)); + result.put("RPC-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + rpcConsumer)); + } catch (Exception e) { + log.warn("monitor controller error: {}", e.getMessage(), e); + } + }); + } return CommonResponse.success(result); } + + /** + * @param status + * @return + */ + @GetMapping("/m/set") + public CommonResponse changeMonitorState(@RequestParam("status") Boolean status) { + if (status) { + if (!monitor.isRunning()) { + monitor.start(); + } + return CommonResponse.success("已临时开始 MQ 死信队列监控!" + + "在应用重启前,将持续监控。重启后,将根据环境变量来确定是否监控。"); + } else { + if (monitor.isRunning()) { + monitor.stop(); + } + return CommonResponse.success("已临时关闭 MQ 死信队列监控!" + + "在应用重启前,将不再监控。重启后,将根据环境变量配置来确定是否监控。"); + } + } } From 1e45bb750a1e7d2f16ff1cefd382cc7c65df4f13 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 18:34:54 +0800 Subject: [PATCH 145/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20MQ=20=E7=9B=91=E6=8E=A7=E7=9A=84=EF=BC=8C=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E6=AD=BB=E4=BF=A1=E9=98=9F=E5=88=97=E7=9A=84=E9=92=A9?= =?UTF-8?q?=E5=AD=90=EF=BC=8C=E5=90=8C=E6=97=B6=EF=BC=8C=E4=B9=9F=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8F=AF=E5=8A=A8=E6=80=81=E5=BC=80=E5=85=B3=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E7=9A=84=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../console/WorkflowEngineStarterMQMonitorController.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index d1689bd5d..733e17039 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; @@ -37,7 +38,7 @@ public class WorkflowEngineStarterMQMonitorController { @Resource private ObjectProvider mqAdminExtObjectProvider; @Resource - private WorkflowEngineStarterDefaultMQMonitor monitor; + private ObjectProvider monitorObjectProvider; @Resource private Environment environment; @Value("${spring.application.name}") @@ -82,6 +83,10 @@ public class WorkflowEngineStarterMQMonitorController { */ @GetMapping("/m/set") public CommonResponse changeMonitorState(@RequestParam("status") Boolean status) { + WorkflowEngineStarterDefaultMQMonitor monitor = monitorObjectProvider.getIfAvailable(); + if (Objects.isNull(monitor)) { + return CommonResponse.success("未开启·死信队列·的监控,如需,请设置 workflow.engine.starter.enableDlqMonitor = true 后再重试!"); + } if (status) { if (!monitor.isRunning()) { monitor.start(); From 6705a7f9f8eb37ab7caf6335342203510bfb1a0c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 18:51:52 +0800 Subject: [PATCH 146/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20MQ=20=E7=9B=91=E6=8E=A7=E7=9A=84=EF=BC=8C=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E6=AD=BB=E4=BF=A1=E9=98=9F=E5=88=97=E7=9A=84=E9=92=A9?= =?UTF-8?q?=E5=AD=90=EF=BC=8C=E5=90=8C=E6=97=B6=EF=BC=8C=E4=B9=9F=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8F=AF=E5=8A=A8=E6=80=81=E5=BC=80=E5=85=B3=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E7=9A=84=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterProperties.java | 18 ++++++++++++++++-- .../WorkflowEngineStarterDefaultMQMonitor.java | 8 +++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 86da8f41d..a549036ec 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -63,9 +63,15 @@ public class WorkflowEngineStarterProperties { private BroadcastListenerProperties broadcast = new BroadcastListenerProperties(); /** - * 是否开始死信队列的监控 + * 是否开始死信队列的监控的特效,不代表真实开始监控,如果需要默认开始,请设置 monitorStatus = true */ - private Boolean enableDlqMonitor = false; + private Boolean enableDlqMonitor = true; + + /** + * 监控状态,默认 false,不真实开始监控 + */ + private Boolean monitorStatus = false; + /** * 监控死信队列,周期间隔,单位:毫秒 */ @@ -119,6 +125,14 @@ public class WorkflowEngineStarterProperties { this.enableDlqMonitor = enableDlqMonitor; } + public Boolean getMonitorStatus() { + return monitorStatus; + } + + public void setMonitorStatus(Boolean monitorStatus) { + this.monitorStatus = monitorStatus; + } + public Long getDlqMonitorIntervalInMs() { return DlqMonitorIntervalInMs; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index bda4ea56c..aef36bd30 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -46,7 +46,8 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, ObjectProvider broadcastDLQProcessorObjectProvider, - ObjectProvider rpcDLQProcessorObjectProvider, Environment environment) { + ObjectProvider rpcDLQProcessorObjectProvider, + Environment environment) { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQProcessor() { @@ -93,6 +94,11 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { } } + @Override + public boolean isAutoStartup() { + return Boolean.TRUE.equals(environment.getProperty("workflow.engine.starter.monitor-status", Boolean.class)); + } + @Override public void start() { if (running.compareAndSet(false, true)) { From 1f8b85956b75db58331a829b74f370b7bc6475f9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 14 Jun 2024 18:59:09 +0800 Subject: [PATCH 147/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20MQ=20=E7=9B=91=E6=8E=A7=E7=9A=84=EF=BC=8C=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E6=AD=BB=E4=BF=A1=E9=98=9F=E5=88=97=E7=9A=84=E9=92=A9?= =?UTF-8?q?=E5=AD=90=EF=BC=8C=E5=90=8C=E6=97=B6=EF=BC=8C=E4=B9=9F=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8F=AF=E5=8A=A8=E6=80=81=E5=BC=80=E5=85=B3=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E7=9A=84=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/WorkflowEngineStarterAutoConfiguration.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index de11113cc..57ba61292 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -42,7 +42,6 @@ import org.springframework.core.env.Environment; import java.util.ArrayList; import java.util.List; -import java.util.Objects; /** * Workflow Engine Auto Configuration @@ -116,7 +115,7 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean(destroyMethod = "shutdown", name = "defaultMQAdminExt") - @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true") + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true", matchIfMissing = true) public DefaultMQAdminExt defaultMQAdminExt(Environment environment) { String namesrvAddress = environment.getProperty("rocketmq.name-server"); if (StringUtils.isBlank(namesrvAddress)) { @@ -140,7 +139,7 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean - @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true") + @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true", matchIfMissing = true) public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, ObjectProvider broadcastDLQProcessorObjectProvider, ObjectProvider rpcDLQProcessorObjectProvider, From cc2626b1a862e94566daf5c7d27ccd130cae6760 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 10:26:08 +0800 Subject: [PATCH 148/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E7=A1=AE=E8=AE=A4=20starter=20=E9=9C=80=E5=BC=80?= =?UTF-8?q?=E6=94=BE=E7=9A=84=E6=8E=A5=E5=8F=A3=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessActivityApi.java | 9 +-------- .../client/feign/bpmn/ProcessInstanceApi.java | 3 ++- .../workflow/client/feign/bpmn/ProcessJobApi.java | 12 ++++++++++++ .../web/bpmn/BpmnProcessActivityController.java | 5 ++--- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 8e49ba593..60354dd7b 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -24,16 +24,9 @@ public interface ProcessActivityApi { /** * 业务节点唤醒 - *

- * TODO 接口需要合并,但需要考虑客户端与服务端不同版本间如何兼容 */ - @GetMapping("/api/process/activity/old/trigger") - CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); - - @Operation(summary = "业务节点唤醒") @GetMapping("/api/process/activity/trigger") - CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, - @RequestParam(required = false, defaultValue = "false") Boolean async); + CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index f634d5714..10df7fec6 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -128,13 +128,14 @@ public interface ProcessInstanceApi { CommonResponse batchAbortProcessInstance(@Validated @RequestBody List dtos); /** - * 抄送流程实例 + * 抄送流程实例(未实现) * * @param dto * @return */ @Operation(summary = "抄送流程实例") @PostMapping("/api/process/instance/carbon-copy") + @Deprecated CommonResponse carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index 8a4169893..f02ea2c9a 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.Manageable; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @@ -9,7 +10,18 @@ import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessJobApi { + /** + * 将死信队列中的任务转移到正常 JOB 队列中 + *

+ * 入参是二选一:当只有 jobId 时,仅将指定的 JOB 转移到正常的队列中; + * 而传入的是具体的实例 ID,那么会将这个流程下的所有在死信队列中的任务都转移到正常的队列中 + * + * @param jobId 具体的 JOB ID + * @param procInstId 具体的实例 ID + * @return + */ @GetMapping("/api/process/job/dead-letter/resume") + @Manageable CommonResponse executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index b9601c36b..d8c34a739 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -49,8 +49,7 @@ public class BpmnProcessActivityController implements ProcessActivityApi { * @return */ @Operation(summary = "业务节点唤醒") - @GetMapping("/trigger") - @Override + @GetMapping("/v2/trigger") @RepeatSubmit public CommonResponse trigger(@RequestParam @NotBlank(message = "触发 ID 不能为空") String triggerId, @RequestParam(required = false, defaultValue = "false") Boolean async) { @@ -64,7 +63,7 @@ public class BpmnProcessActivityController implements ProcessActivityApi { } @Operation(summary = "业务节点唤醒") - @GetMapping("/old/trigger") + @GetMapping("/trigger") @Override @RepeatSubmit public CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId) { From 804d3e31f2dd903ea6ba32cd6511cc238b525c6f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 10:26:50 +0800 Subject: [PATCH 149/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=94=9F=E6=88=90=EF=BC=8C=E6=96=B0=E5=A2=9E=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/support/api/CoreServiceCodeGeneration.java | 4 +++- .../workflow/support/api/ManageServiceCodeGeneration.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java index c313d1728..bb486ff9e 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java @@ -8,6 +8,7 @@ import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.BodyDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.ast.expr.ClassExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; @@ -167,7 +168,8 @@ public class CoreServiceCodeGeneration { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); - classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service"); + classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service
" + + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index ffa4a7831..c5ceff26b 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -158,7 +158,8 @@ public class ManageServiceCodeGeneration { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); - classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service"); + classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service
" + + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) From 3797b3d8b1481f59f23cf099e3a38a1ded970bb5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 10:27:17 +0800 Subject: [PATCH 150/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E6=96=B0=E7=9A=84=E4=B8=80=E7=89=88=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 16 ++++------------ .../starter/api/WorkflowManageService.java | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 287ee06e6..52fbc69ba 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -56,22 +56,16 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import javax.validation.constraints.NotEmpty; /** - * Workflow Engine Starter Core Service + * Workflow Engine Starter Core Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ @FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { /** * 业务节点唤醒 - *

- * TODO 接口需要合并,但需要考虑客户端与服务端不同版本间如何兼容 */ - @GetMapping("/api/process/activity/old/trigger") - Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); - - @Operation(summary = "业务节点唤醒") @GetMapping("/api/process/activity/trigger") - Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId, @RequestParam(required = false, defaultValue = "false") Boolean async); + Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); /** * 业务节点设置审批人, 不支持重复设置 @@ -136,13 +130,14 @@ public interface WorkflowCoreService { BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); /** - * 抄送流程实例 + * 抄送流程实例(未实现) * * @param dto * @return */ @Operation(summary = "抄送流程实例") @PostMapping("/api/process/instance/carbon-copy") + @Deprecated Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); /** @@ -166,9 +161,6 @@ public interface WorkflowCoreService { @GetMapping("/api/process/instance/cooperation-org") Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - @GetMapping("/api/process/job/dead-letter/resume") - Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); - /** * 同意 * diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 1b3c52732..cd89a0560 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -74,7 +74,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionP import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; /** - * Workflow Engine Starter Management Service + * Workflow Engine Starter Management Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ @FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { @@ -309,6 +309,20 @@ public interface WorkflowManageService { @Manageable Boolean checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); + /** + * 将死信队列中的任务转移到正常 JOB 队列中 + *

+ * 入参是二选一:当只有 jobId 时,仅将指定的 JOB 转移到正常的队列中; + * 而传入的是具体的实例 ID,那么会将这个流程下的所有在死信队列中的任务都转移到正常的队列中 + * + * @param jobId 具体的 JOB ID + * @param procInstId 具体的实例 ID + * @return + */ + @GetMapping("/api/process/job/dead-letter/resume") + @Manageable + Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + /** * 获取指定业务分类 * From 6bd14a59bdd14075934c9f30b87807f4f4b52412 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 11:37:43 +0800 Subject: [PATCH 151/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=B0=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E6=8E=A5=E5=8F=A3=E7=9A=84=E5=85=A5=E5=8F=82?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=A2=9E=E5=8A=A0=20builder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpmn/process/BpmnBasicProcessInstanceQueryDTO.java | 6 ++++++ .../request/bpmn/process/BpmnProcessInstanceAbortDTO.java | 6 ++++++ .../request/bpmn/process/BpmnProcessInstanceCancelDTO.java | 6 ++++++ .../bpmn/process/BpmnProcessInstanceCarbonCopyDTO.java | 6 ++++++ .../request/bpmn/process/BpmnProcessInstanceCreateDTO.java | 6 ++++++ .../request/bpmn/process/BpmnProcessInstanceQueryDTO.java | 3 +++ .../model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java | 6 ++++++ .../model/request/bpmn/task/BpmnRobotTaskCompleteDTO.java | 6 ++++++ .../model/request/bpmn/task/BpmnRobotTaskCreateDTO.java | 6 ++++++ .../common/model/request/bpmn/task/BpmnTaskAuditDTO.java | 6 ++++++ .../common/model/request/bpmn/task/BpmnTaskCommentDTO.java | 6 ++++++ .../model/request/bpmn/task/BpmnTaskCountersignDTO.java | 6 ++++++ .../common/model/request/bpmn/task/BpmnTaskTransferDTO.java | 6 ++++++ 13 files changed, 75 insertions(+) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnBasicProcessInstanceQueryDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnBasicProcessInstanceQueryDTO.java index 4abf1f7f8..8b770bb76 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnBasicProcessInstanceQueryDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnBasicProcessInstanceQueryDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.process; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import javax.annotation.Nullable; @@ -17,6 +20,9 @@ import javax.validation.constraints.NotBlank; @ApiModel("最基础的流程实例查询入参模型") @Data @Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnBasicProcessInstanceQueryDTO { /** * 流程实例 ID diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceAbortDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceAbortDTO.java index 9f201a93a..734b7651b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceAbortDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceAbortDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.process; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotBlank; @@ -15,6 +18,9 @@ import javax.validation.constraints.NotBlank; */ @ApiModel("中止流程实例的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnProcessInstanceAbortDTO { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java index efae1c772..5b44b327c 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java @@ -3,7 +3,10 @@ package cn.axzo.workflow.common.model.request.bpmn.process; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -17,6 +20,9 @@ import javax.validation.constraints.NotNull; */ @ApiModel("取消流程实例的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnProcessInstanceCancelDTO { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCarbonCopyDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCarbonCopyDTO.java index 963fb2a3f..bf558b9a0 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCarbonCopyDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCarbonCopyDTO.java @@ -4,7 +4,10 @@ import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; @@ -18,6 +21,9 @@ import java.util.List; */ @ApiModel("抄送流程实例的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnProcessInstanceCarbonCopyDTO { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java index 47e979c87..c5c7fa2ee 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java @@ -4,7 +4,10 @@ import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotEmpty; @@ -17,6 +20,9 @@ import java.util.Map; */ @ApiModel("创建流程实例的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnProcessInstanceCreateDTO { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceQueryDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceQueryDTO.java index 8a445e11b..013ec1689 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceQueryDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceQueryDTO.java @@ -2,8 +2,11 @@ package cn.axzo.workflow.common.model.request.bpmn.process; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java index 32dd5fec4..7ddf139f7 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -16,6 +19,9 @@ import java.util.List; */ @ApiModel("业务节点设置审批人") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnActivitySetAssigneeDTO { /** * PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件中的触发 ID diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCompleteDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCompleteDTO.java index 13eab3eec..046387245 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCompleteDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCompleteDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -15,6 +18,9 @@ import javax.validation.constraints.NotBlank; */ @ApiModel("完成机器人节点的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnRobotTaskCompleteDTO { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCreateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCreateDTO.java index 7f3b9cd6b..df45977c1 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCreateDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnRobotTaskCreateDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -16,6 +19,9 @@ import javax.validation.constraints.NotNull; */ @ApiModel("创建机器人节点的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnRobotTaskCreateDTO { /** * 流程实例 ID diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java index b841e5b88..d1c7a3638 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java @@ -3,7 +3,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; import javax.validation.Valid; @@ -19,6 +22,9 @@ import java.util.List; @ApiModel("审批任务节点的入参模型") @Data @Validated +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnTaskAuditDTO { @ApiModelProperty(value = "任务编号", required = true, example = "1024") diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCommentDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCommentDTO.java index 2f02ecbcb..78aaf766c 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCommentDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCommentDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; import javax.validation.Valid; @@ -19,6 +22,9 @@ import java.util.List; */ @ApiModel("评论的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnTaskCommentDTO implements Serializable { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCountersignDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCountersignDTO.java index 537d25e15..2dc711af6 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCountersignDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskCountersignDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import javax.validation.Valid; @@ -21,6 +24,9 @@ import java.util.List; */ @Data @Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnTaskCountersignDTO implements Serializable { private static final long serialVersionUID = -8106887960942113552L; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskTransferDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskTransferDTO.java index f91c54403..54fb509fc 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskTransferDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskTransferDTO.java @@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -16,6 +19,9 @@ import java.util.List; */ @ApiModel("转交审批任务的入参模型") @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class BpmnTaskTransferDTO { /** From 2581d69ef9776773659e6d36becd136f069f9c45 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 17:36:48 +0800 Subject: [PATCH 152/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20API=20=E6=8E=A5=E5=8F=A3=E9=A1=BA=E5=BA=8F=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessActivityApi.java | 6 + .../client/feign/bpmn/ProcessInstanceApi.java | 82 ++++++------- .../client/feign/bpmn/ProcessTaskApi.java | 116 +++++++++--------- 3 files changed, 105 insertions(+), 99 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 60354dd7b..3f5fca64d 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -24,6 +24,8 @@ public interface ProcessActivityApi { /** * 业务节点唤醒 + *

+ * 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行 */ @GetMapping("/api/process/activity/trigger") CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); @@ -31,6 +33,10 @@ public interface ProcessActivityApi { /** * 业务节点设置审批人, 不支持重复设置 + *

+ * 当模型中使用了“业务节点”,且设置了“业务指定审批人”模式,则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时,可通过该接口设置动态设置审批人 + *

+ * 注意:如果调用接口时,传入的审批人集合为空,流程引擎将对该审批流程实例自动中止。 * * @param dto * @return diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index 10df7fec6..84e761133 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -46,24 +46,6 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; */ @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessInstanceApi { - /** - * 查询所有的审批流 - * - * @return - */ - @Operation(summary = "查询所有的审批流") - @PostMapping("/api/process/instance/page/all") - @Manageable - CommonResponse> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); - - /** - * 我发起的审批列表 - */ - @Operation(summary = "我发起的审批列表") - @PostMapping("/api/process/instance/page/my") - @Manageable - CommonResponse> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); - /** * 创建审批流程 * @@ -80,17 +62,6 @@ public interface ProcessInstanceApi { @InvokeMode(SYNC) CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); - /** - * 创建审批流程并带上表单 - * - * @param dto - * @return - */ - @Operation(summary = "创建审批流程并带上表单") - @PostMapping("/api/process/instance/form/create") - @Manageable - CommonResponse createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); - /** * 发起人主动撤回审核 * @@ -148,6 +119,47 @@ public interface ProcessInstanceApi { @GetMapping("/api/process/instance/get") CommonResponse getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + /** + * 获取指定流程实例的流程变量 + * + * @param processInstanceId + * @param tenantId + * @return + */ + @Operation(summary = "获取指定流程实例的流程变量") + @GetMapping("/api/process/instance/cooperation-org") + CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @Nullable @RequestParam(required = false) String tenantId); + + /** + * 创建审批流程并带上表单 + * + * @param dto + * @return + */ + @Operation(summary = "创建审批流程并带上表单") + @PostMapping("/api/process/instance/form/create") + @Manageable + CommonResponse createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); + + /** + * 查询所有的审批流 + * + * @return + */ + @Operation(summary = "查询所有的审批流") + @PostMapping("/api/process/instance/page/all") + @Manageable + CommonResponse> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); + + /** + * 我发起的审批列表 + */ + @Operation(summary = "我发起的审批列表") + @PostMapping("/api/process/instance/page/my") + @Manageable + CommonResponse> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); + /** * 更新流程定义的状态 * @@ -199,18 +211,6 @@ public interface ProcessInstanceApi { @RequestParam(required = false, defaultValue = "false") Boolean allNode, @Nullable @RequestParam(required = false) List nodeDefinitionKeys); - /** - * 获取指定流程实例的流程变量 - * - * @param processInstanceId - * @param tenantId - * @return - */ - @Operation(summary = "获取指定流程实例的流程变量") - @GetMapping("/api/process/instance/cooperation-org") - CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId); - /** * 查询实例的租户集合 * diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 8193ab5d8..9cfd544b8 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -43,53 +43,6 @@ import java.util.Map; @FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessTaskApi { - /** - * 待审核列表 - */ - @Operation(summary = "待审核列表") - @GetMapping("/api/process/task/page/todo") - @Manageable - CommonResponse> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); - - /** - * 已完成的审批列表 - */ - @Operation(summary = "已完成的审批列表") - @GetMapping("/api/process/task/page/done") - @Manageable - CommonResponse> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); - - /** - * 获取指定流程实例的审批过程信息 - *

- * 同一层级结构 - */ - @Operation(summary = "获取指定流程实例的审批过程信息") - @GetMapping("/api/process/task/list/flat") - @Manageable - CommonResponse> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + - "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 获取指定流程实例的审批过程信息 - *

- * 分组结构 - */ - @Operation(summary = "获取指定流程实例的审批过程信息") - @GetMapping("/api/process/task/list/group") - @Manageable - CommonResponse> getTaskListGroupByProcessInstanceId(@NotBlank(message = - "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 获取实例正在审核的人列表 - */ - @Operation(summary = "获取实例正在审核的人列表") - @GetMapping("/api/process/task/active/list") - @Manageable - CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @NotBlank(message = "租户不能为空") @RequestParam String tenantId); - /** * 同意 * @@ -167,17 +120,6 @@ public interface ProcessTaskApi { @PostMapping("/api/process/task/comment") CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); - /** - * 添加附件 - * - * @param dto - * @return - */ - @Operation(summary = "添加附件") - @PostMapping("/api/process/task/attachment") - @Manageable - CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); - /** * 加签 * @@ -219,6 +161,64 @@ public interface ProcessTaskApi { @PostMapping("/api/process/task/robot/complete") CommonResponse completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); + /** + * 添加附件 + * + * @param dto + * @return + */ + @Operation(summary = "添加附件") + @PostMapping("/api/process/task/attachment") + @Manageable + CommonResponse addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); + + /** + * 待审核列表 + */ + @Operation(summary = "待审核列表") + @GetMapping("/api/process/task/page/todo") + @Manageable + CommonResponse> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); + + /** + * 已完成的审批列表 + */ + @Operation(summary = "已完成的审批列表") + @GetMapping("/api/process/task/page/done") + @Manageable + CommonResponse> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); + + /** + * 获取指定流程实例的审批过程信息 + *

+ * 同一层级结构 + */ + @Operation(summary = "获取指定流程实例的审批过程信息") + @GetMapping("/api/process/task/list/flat") + @Manageable + CommonResponse> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取指定流程实例的审批过程信息 + *

+ * 分组结构 + */ + @Operation(summary = "获取指定流程实例的审批过程信息") + @GetMapping("/api/process/task/list/group") + @Manageable + CommonResponse> getTaskListGroupByProcessInstanceId(@NotBlank(message = + "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取实例正在审核的人列表 + */ + @Operation(summary = "获取实例正在审核的人列表") + @GetMapping("/api/process/task/active/list") + @Manageable + CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, + @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + /** * 根据实例 ID 和自然人 ID 查询对应待处理的任务 ID * From ff1d5e2e8ed0725901200d5b0380bf4118559685 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 17:37:12 +0800 Subject: [PATCH 153/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=8E=A5=E5=8F=A3=E6=A8=A1=E5=9E=8B=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20Builder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/dto/CooperationOrgDTO.java | 1 + .../bpmn/process/BpmnProcessInstanceCreateDTO.java | 13 +++---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java index 507c9f8c1..858e68eb3 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java @@ -20,6 +20,7 @@ import java.util.List; @Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor +@Builder public class CooperationOrgDTO implements Serializable { private static final long serialVersionUID = 4739924705980062997L; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java index c5c7fa2ee..80c33308d 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java @@ -34,7 +34,7 @@ public class BpmnProcessInstanceCreateDTO { /** * 流程定义的标识 *

- * [对应业务分类的 businessId] + * [对应 OMS 系统中审批业务的业务 ID] */ @NotEmpty(message = "流程定义的标识不能为空") private String processDefinitionKey; @@ -62,6 +62,7 @@ public class BpmnProcessInstanceCreateDTO { *

* 用于流程引擎计算对应节点的审批人, 例如第一个审批节点配置的是劳务分包的岗位,第二个审批节点配置的专业分包的角色, * 那么, 组织关系就需要传入劳务分包的信息以及专业分包的信息,如果还有更多的审批节点配置,以此类推. + * 同时,该属性还会用于计算抄送人,以及消息通知的目标接收人 */ @ApiModelProperty(value = "组织关系") @NotNull(message = "组织关系不能为空") @@ -87,17 +88,9 @@ public class BpmnProcessInstanceCreateDTO { private String customProcessInstanceName; /** - * 是否异步执行 + * 是否异步执行,该异步是引擎的一种运行模式 */ @ApiModelProperty(value = "是否异步", notes = "异步时,只接收请求便返回数据") private Boolean async = true; - /** - * 废弃 - * 下级审批人 - */ - // @ApiModelProperty(value = "下级审批人", notes = "可为空,定义选择审批人,如果不为空,则覆盖下一级任务的审核人") - // @Deprecated - // private BpmnTaskDelegateAssigner nextApprover; - } From 884d60c2b15ffbf18624730d024698c2e9bfc298 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 17:38:07 +0800 Subject: [PATCH 154/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=BB=86?= =?UTF-8?q?=E5=8C=96=20Starter=20=E5=AF=B9=20MQ=20=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/BroadcastListenerProperties.java | 17 ++++++++- ...orkflowEngineStarterAutoConfiguration.java | 3 +- .../WorkflowEngineStarterProperties.java | 24 ++++++------ .../starter/api/WorkflowCoreService.java | 6 +++ ...WorkflowEngineStarterDefaultMQMonitor.java | 37 ++++++++++++++----- .../resources/META-INF/application.yml.demo | 4 ++ 6 files changed, 66 insertions(+), 25 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java index 412cc41a6..d14a8ce74 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java @@ -35,11 +35,11 @@ public class BroadcastListenerProperties { * * 业务 ID:从 OMS 平台中的“审批业务”查看, *

-     * 
+     * 
      * 
* 或者从“审批模板”中“业务 ID”进行查看 *
-     *     
+     *     
      * 
*/ private Boolean enableFilterDefinitionKey = false; @@ -63,6 +63,11 @@ public class BroadcastListenerProperties { */ private FailHandleTypeEnum failHandleType = FAIL_OVER; + /** + * 广播的 DLQ 监控 + */ + private Boolean monitorStatus = false; + /** * 自动重试次数 */ @@ -118,6 +123,14 @@ public class BroadcastListenerProperties { this.failHandleType = failHandleType; } + public Boolean getMonitorStatus() { + return monitorStatus; + } + + public void setMonitorStatus(Boolean monitorStatus) { + this.monitorStatus = monitorStatus; + } + public int getNumOfRetries() { return numOfRetries; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 57ba61292..26e872391 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -143,7 +143,8 @@ public class WorkflowEngineStarterAutoConfiguration { public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, ObjectProvider broadcastDLQProcessorObjectProvider, ObjectProvider rpcDLQProcessorObjectProvider, + WorkflowEngineStarterProperties workflowEngineStarterProperties, Environment environment) { - return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, broadcastDLQProcessorObjectProvider, rpcDLQProcessorObjectProvider, environment); + return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, broadcastDLQProcessorObjectProvider, rpcDLQProcessorObjectProvider, workflowEngineStarterProperties, environment); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index a549036ec..2fcfe42a5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -63,19 +63,19 @@ public class WorkflowEngineStarterProperties { private BroadcastListenerProperties broadcast = new BroadcastListenerProperties(); /** - * 是否开始死信队列的监控的特效,不代表真实开始监控,如果需要默认开始,请设置 monitorStatus = true + * 是否开启死信队列的监控的特性,不代表真实开始监控,如果需要默认开始,请设置 monitorStatus = true */ private Boolean enableDlqMonitor = true; /** - * 监控状态,默认 false,不真实开始监控 + * 监控状态,默认 true,真实开始监控 RPC 的私信队列监控 */ - private Boolean monitorStatus = false; + private Boolean rpcMonitorStatus = true; /** * 监控死信队列,周期间隔,单位:毫秒 */ - private Long DlqMonitorIntervalInMs = 4 * 60 * 60 * 1000L; + private long dlqMonitorIntervalInMs = 4 * 60 * 60 * 1000L; public Boolean getManageable() { return manageable; @@ -125,19 +125,19 @@ public class WorkflowEngineStarterProperties { this.enableDlqMonitor = enableDlqMonitor; } - public Boolean getMonitorStatus() { - return monitorStatus; + public Boolean getRpcMonitorStatus() { + return rpcMonitorStatus; } - public void setMonitorStatus(Boolean monitorStatus) { - this.monitorStatus = monitorStatus; + public void setRpcMonitorStatus(Boolean rpcMonitorStatus) { + this.rpcMonitorStatus = rpcMonitorStatus; } - public Long getDlqMonitorIntervalInMs() { - return DlqMonitorIntervalInMs; + public long getDlqMonitorIntervalInMs() { + return dlqMonitorIntervalInMs; } - public void setDlqMonitorIntervalInMs(Long dlqMonitorIntervalInMs) { - DlqMonitorIntervalInMs = dlqMonitorIntervalInMs; + public void setDlqMonitorIntervalInMs(long dlqMonitorIntervalInMs) { + this.dlqMonitorIntervalInMs = dlqMonitorIntervalInMs; } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 52fbc69ba..67ce136d0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -63,12 +63,18 @@ public interface WorkflowCoreService { /** * 业务节点唤醒 + *

+ * 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行 */ @GetMapping("/api/process/activity/trigger") Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); /** * 业务节点设置审批人, 不支持重复设置 + *

+ * 当模型中使用了“业务节点”,且设置了“业务指定审批人”模式,则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时,可通过该接口设置动态设置审批人 + *

+ * 注意:如果调用接口时,传入的审批人集合为空,流程引擎将对该审批流程实例自动中止。 * * @param dto * @return diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index aef36bd30..d5ebef0c0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.mq.monitor; +import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQProcessor; import cn.axzo.workflow.starter.handler.monitor.RpcDLQProcessor; import lombok.SneakyThrows; @@ -13,11 +14,8 @@ import org.springframework.core.env.Environment; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.BROADCAST_CONSUMER_GROUP; @@ -33,6 +31,8 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private static final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterDefaultMQMonitor.class); public static final String DLQ_PREFIX = "%DLQ%"; + private static final String BROADCAST = "broadcast"; + private static final String RPC = "rpc"; /** * 可能为 null */ @@ -41,12 +41,13 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private final ThreadPoolTaskScheduler taskScheduler; private final BroadcastDLQProcessor broadcastDLQProcessor; private final RpcDLQProcessor rpcDLQProcessor; + private final WorkflowEngineStarterProperties starterProperties; private final AtomicBoolean running = new AtomicBoolean(false); - private final Map> dlqProcessCache = new HashMap<>(); public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, ObjectProvider broadcastDLQProcessorObjectProvider, ObjectProvider rpcDLQProcessorObjectProvider, + WorkflowEngineStarterProperties workflowEngineStarterProperties, Environment environment) { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; @@ -54,6 +55,7 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { }); this.rpcDLQProcessor = rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQProcessor() { }); + this.starterProperties = workflowEngineStarterProperties; this.taskScheduler = init(); } @@ -66,14 +68,23 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { @SneakyThrows public void mqWatch() { + mqWatch(BROADCAST); + mqWatch(RPC); + } + + @SneakyThrows + public void mqWatch(String type) { String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); String applicationName = environment.getProperty("spring.application.name"); // 周期性比对 - compareDLQ(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment), "broadcast"); - compareDLQ(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment), "rpc"); + if (Objects.equals(type, BROADCAST)) { + compareDLQ(String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment), type); + } else if (Objects.equals(type, RPC)) { + compareDLQ(String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment), type); + } } - private void compareDLQ(String consumerGroupName, String dqlType) throws Exception { + private void compareDLQ(String consumerGroupName, String dqlType) { log.info("current broadcast consumer group is :{}", consumerGroupName); try { TopicStatsTable table = defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + consumerGroupName); @@ -82,9 +93,9 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { } table.getOffsetTable().forEach((k, v) -> { if (Objects.equals(DLQ_PREFIX + consumerGroupName, k.getTopic())) { - if ("broadcast".equals(dqlType)) { + if (BROADCAST.equals(dqlType)) { broadcastDLQProcessor.process(v); - } else if ("rpc".equals(dqlType)) { + } else if (RPC.equals(dqlType)) { rpcDLQProcessor.process(v); } } @@ -96,7 +107,13 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { @Override public boolean isAutoStartup() { - return Boolean.TRUE.equals(environment.getProperty("workflow.engine.starter.monitor-status", Boolean.class)); + if (starterProperties.getEnableDlqMonitor() && starterProperties.getRpcMonitorStatus()) { + taskScheduler.scheduleWithFixedDelay(() -> mqWatch(BROADCAST), starterProperties.getDlqMonitorIntervalInMs()); + } + if (starterProperties.getEnableDlqMonitor() && starterProperties.getBroadcast().getMonitorStatus()) { + taskScheduler.scheduleWithFixedDelay(() -> mqWatch(RPC), starterProperties.getDlqMonitorIntervalInMs()); + } + return false; } @Override diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo index af6c7214e..9e64ea2a5 100644 --- a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo @@ -4,6 +4,9 @@ workflow: invoke-mode: async # 调用 workflowCoreService 中方法的方式,可选值:sync、async join-container-group: false # 本地开发机启动时,是否将 MQ 消费者加入到集群中,默认不加入,并默认生成 GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_debugging_consumer 的消费者组,该参数只对非容器环境生效 manageable: false # 是否可管理,默认 false, 开启后 Spring 容器中将多一个 WorkflowManageService 的 Bean,可调用受限访问接口 + enable-dlq-monitor: true # 是否启用 starter 中使用到的死信队列监控功能,仅是启动功能,未真实监控,需要配合 monitor-status = true 使用 + monitor-status: false # 应用启动后,如果该属性为 true,则真实启动监控,否则不启动 + dql-monitor-interval-in-ms: 4 * 60 * 60 * 1000 # 周期性获取死信队列监控信息的间隔时间 broadcast: # 关于 Starter 中监听引擎广播的事件相关配置 enable-filter-application-name: false # 过滤广播事件,只接收来自指定应用名的创建的流程的广播事件,默认 false,不进行过滤。如果为 true,则将配合 filter-application-names 参数进行广播事件的过滤。该过滤功能的前提是使用了 1.4.0 及以上版本的 workflow-engine-spring-boot-starter.jar filter-application-names: # 配合 enable-filter-application-name 属性,当它为 true 时,该参数生效。设置的值为需要消费的 MQ 事件 @@ -12,6 +15,7 @@ workflow: filter-process-definition-keys: # 配合 enable-filter-definition-key 属性,当它为 true 时,该参数生效。设置的值为需要消费的 MQ 事件 - '1' fail-handle-type: fail_over # 广播事件失败时,如何处理。可选值:fail_over(会按下面三个属性进行重试)、fail_fast(直接打印异常,跳过该消息的消费) + monitor-status: false # 广播 MQ 的私信队列监控 num-of-retries: # 当 fail-handle-type 为 fail_over 时,广播事件失败时,重试次数 wait-increase-factor: # 当 fail-handle-type 为 fail_over 时,广播事件失败时,重试间隔时间增长因子 wait-time-in-ms: # 当 fail-handle-type 为 fail_over 时,广播事件失败时,重试间隔时间 From a21b4eec1058ab1948269df72e7a889a399e4a2c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 17:50:18 +0800 Subject: [PATCH 155/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=B8=80=E4=BA=9B=E7=B1=BB=E5=91=BD=E5=90=8D=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E5=85=B6=E5=90=AB=E4=B9=89=E6=9B=B4=E7=B2=BE=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterAutoConfiguration.java | 8 ++++---- ...QProcessor.java => BroadcastDLQReporter.java} | 6 +++--- ...{RpcDLQProcessor.java => RpcDLQReporter.java} | 6 +++--- .../WorkflowEngineStarterDefaultMQMonitor.java | 16 ++++++++-------- 4 files changed, 18 insertions(+), 18 deletions(-) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/{BroadcastDLQProcessor.java => BroadcastDLQReporter.java} (78%) rename workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/{RpcDLQProcessor.java => RpcDLQReporter.java} (79%) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 26e872391..e13b58eb2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -16,8 +16,8 @@ import cn.axzo.workflow.starter.handler.filter.MessageNotificationEventFilter; import cn.axzo.workflow.starter.handler.filter.ProcessActivityEventFilter; import cn.axzo.workflow.starter.handler.filter.ProcessInstanceEventFilter; import cn.axzo.workflow.starter.handler.filter.ProcessTaskEventFilter; -import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQProcessor; -import cn.axzo.workflow.starter.handler.monitor.RpcDLQProcessor; +import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQReporter; +import cn.axzo.workflow.starter.handler.monitor.RpcDLQReporter; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerActivityEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerInstanceEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventListener; @@ -141,8 +141,8 @@ public class WorkflowEngineStarterAutoConfiguration { @Bean @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true", matchIfMissing = true) public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, - ObjectProvider broadcastDLQProcessorObjectProvider, - ObjectProvider rpcDLQProcessorObjectProvider, + ObjectProvider broadcastDLQProcessorObjectProvider, + ObjectProvider rpcDLQProcessorObjectProvider, WorkflowEngineStarterProperties workflowEngineStarterProperties, Environment environment) { return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, broadcastDLQProcessorObjectProvider, rpcDLQProcessorObjectProvider, workflowEngineStarterProperties, environment); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java similarity index 78% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java index 3edc50ea1..e5689a4db 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQProcessor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java @@ -5,7 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * 广播死信队列监控的处理器, 默认仅仅是打印异常。 + * 广播死信队列监控的报告器, 默认仅仅是打印异常。 *

* 可以用它来发生钉钉之类的。 *

@@ -14,8 +14,8 @@ import org.slf4j.LoggerFactory; * @author wangli * @since 2024/6/14 17:04 */ -public interface BroadcastDLQProcessor { - Logger log = LoggerFactory.getLogger(BroadcastDLQProcessor.class); +public interface BroadcastDLQReporter { + Logger log = LoggerFactory.getLogger(BroadcastDLQReporter.class); default void process(TopicOffset v) { long dlqCount = v.getMaxOffset() - v.getMinOffset(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java similarity index 79% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java rename to workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java index 6aeaa49f7..9ce1e7a01 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQProcessor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java @@ -5,7 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * RPC 重试的死信队列监控处理器, 默认仅仅是打印异常 + * RPC 重试的死信队列监控报告器, 默认仅仅是打印异常 *

* 可以用它来发生钉钉之类的. *

@@ -15,8 +15,8 @@ import org.slf4j.LoggerFactory; * @since 2024/6/14 17:01 */ -public interface RpcDLQProcessor { - Logger log = LoggerFactory.getLogger(RpcDLQProcessor.class); +public interface RpcDLQReporter { + Logger log = LoggerFactory.getLogger(RpcDLQReporter.class); default void process(TopicOffset v) { long dlqCount = v.getMaxOffset() - v.getMinOffset(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index d5ebef0c0..51ac42f10 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -1,8 +1,8 @@ package cn.axzo.workflow.starter.mq.monitor; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQProcessor; -import cn.axzo.workflow.starter.handler.monitor.RpcDLQProcessor; +import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQReporter; +import cn.axzo.workflow.starter.handler.monitor.RpcDLQReporter; import lombok.SneakyThrows; import org.apache.rocketmq.common.admin.TopicStatsTable; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; @@ -39,21 +39,21 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private final DefaultMQAdminExt defaultMQAdminExt; private final Environment environment; private final ThreadPoolTaskScheduler taskScheduler; - private final BroadcastDLQProcessor broadcastDLQProcessor; - private final RpcDLQProcessor rpcDLQProcessor; + private final BroadcastDLQReporter broadcastDLQProcessor; + private final RpcDLQReporter rpcDLQProcessor; private final WorkflowEngineStarterProperties starterProperties; private final AtomicBoolean running = new AtomicBoolean(false); public WorkflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, - ObjectProvider broadcastDLQProcessorObjectProvider, - ObjectProvider rpcDLQProcessorObjectProvider, + ObjectProvider broadcastDLQProcessorObjectProvider, + ObjectProvider rpcDLQProcessorObjectProvider, WorkflowEngineStarterProperties workflowEngineStarterProperties, Environment environment) { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; - this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQProcessor() { + this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQReporter() { }); - this.rpcDLQProcessor = rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQProcessor() { + this.rpcDLQProcessor = rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQReporter() { }); this.starterProperties = workflowEngineStarterProperties; this.taskScheduler = init(); From 872999d51d70630e9dafa5209fb3c98a97642e14 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 21:01:16 +0800 Subject: [PATCH 156/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B5=8B=E8=AF=95=E8=BF=87=E7=A8=8B=E4=B8=AD=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=E7=9A=84=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/BroadcastListenerProperties.java | 4 ++-- .../starter/StarterBroadcastMQConfiguration.java | 3 +++ .../starter/StarterRPCInvokeMQConfiguration.java | 3 +-- .../exception/WorkflowEngineStarterException.java | 4 ++++ .../execute/interceptor/FailFastInterceptor.java | 6 ++---- .../execute/interceptor/FailOverInterceptor.java | 6 +++--- .../handler/execute/interceptor/LogInterceptor.java | 10 ++++++++++ .../monitor/WorkflowEngineStarterDefaultMQMonitor.java | 4 ++-- 8 files changed, 27 insertions(+), 13 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java index d14a8ce74..679d752bd 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/BroadcastListenerProperties.java @@ -56,8 +56,8 @@ public class BroadcastListenerProperties { /** * 失败处理策略: *

-     * 1、FAIL_OVER, 当前listener执行出错,在经历重试后,不抛出异常,忽略继续往下执行(默认策略)
-     * 2、FAIL_FAST, 快速失败,出错直接抛出异常,listener不再往下执行
+     * 1、FAIL_OVER, 当前listener执行出错,在经历重试后,抛出异常,并将消息加入死信队列,然后继续往下执行(默认策略)
+     * 2、FAIL_FAST, 快速失败,不管内部是什么异常类型,都将吞掉异常,正确结束,不会增加死信队列计数
      * 3、FAIL_BACK, 失败自动恢复,在后台记录失败的消息,并按照一定的策略后期再进行重试,目前暂不支持
      * 
*/ diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 3741d12e1..9ac804265 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -6,6 +6,7 @@ import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandlerRepository; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; +import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.handler.filter.global.BroadcastMessageQueueFilter; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.WorkflowEngineBroadcastEventListener; @@ -60,6 +61,8 @@ public class StarterBroadcastMQConfiguration { // 不管 cn.axzo.workflow.starter.BroadcastListenerProperties.failHandleType 设置是哪种策略,这里最终都会打印 WARN 级别日志,框架底层会对所有异常的消息打印 ERROR 日志 // 如果不想打印需要扩展内部逻辑,请主动注册自己扩展的 Bean,且名称为 StarterBroadcastMQConfiguration.BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME log.warn("Workflow Engine Starter MQ, an exception occurred during processing {}", logText, ex); + // 让其进入死信队列 + throw new WorkflowEngineStarterException(ex); }); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 2a291e8bc..aa9854aeb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -164,8 +164,7 @@ public class StarterRPCInvokeMQConfiguration { @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", consumeMode = ConsumeMode.CONCURRENTLY, - maxReconsumeTimes = 7, // 发布时需调整为 7, 总共耗时在 15min 内 - replyTimeout = 10000, + maxReconsumeTimes = 7, // 发布时需调整为 7, 总共耗时在 15min 内, 目前容器为滚动发布,一版不会出现停机这么久 nameServer = "${rocketmq.name-server}" ) public static class WorkflowEngineStarterRetryConsumer extends BaseListener implements RocketMQListener, InitializingBean { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java index 2cf0712b7..cf4244523 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowEngineStarterException.java @@ -8,6 +8,10 @@ package cn.axzo.workflow.starter.common.exception; */ public class WorkflowEngineStarterException extends RuntimeException { + public WorkflowEngineStarterException(Throwable cause) { + super(cause); + } + public WorkflowEngineStarterException(String message) { super(message); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java index bd432e078..77b46c5a0 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailFastInterceptor.java @@ -15,11 +15,9 @@ public final class FailFastInterceptor extends AbstractListenerInterceptor { public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { try { getNext().execute(executor, consumer, context, t); - } catch (Exception e) { + } catch (Throwable e) { throw new WorkflowListenerExecutionException( - "Failed to invoke the method " -// + methodName - + ". Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); + "Failed to invoke the method. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java index 342640fba..0eb2659fc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/FailOverInterceptor.java @@ -29,8 +29,8 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { @Override public void execute(ListenerExecutor executor, Consumer consumer, EventConsumer.Context context, T t) { - // 避免组件抛出“程序处理超时”的异常信息 - context.setMaxAllowElapsedMillis(calc() + 500L); + // 避免组件抛出“程序处理超时”的异常信息, 为业务冗余 10 处理时间 + context.setMaxAllowElapsedMillis(calc() + 10_000L); long waitTime = waitTimeInMs; int failedAttempts = 0; do { @@ -42,7 +42,7 @@ public final class FailOverInterceptor extends AbstractListenerInterceptor { try { getNext().execute(executor, consumer, context, t); return; - } catch (Exception e) { + } catch (Throwable e) { if (failedAttempts == numOfRetries) { log.error("Workflow Engine Starter caught exception: {}", e.getMessage(), e); throw e; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java index 665e7bf84..1ff75e8ad 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/execute/interceptor/LogInterceptor.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.starter.handler.execute.interceptor; import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; +import cn.axzo.workflow.starter.common.exception.WorkflowListenerExecutionException; import cn.axzo.workflow.starter.handler.execute.ListenerExecutor; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; @@ -24,6 +26,14 @@ public final class LogInterceptor extends AbstractListenerInterceptor { } try { getNext().execute(executor, consumer, context, t); + } catch (WorkflowListenerExecutionException e) { + // fail_fast mode , will be ignored + } catch (Throwable e) { + if (e instanceof WorkflowEngineStarterException) { + // 如果业务想使用异常来正确结束事件处理,可以抛出该移除类型 + } else { + throw e; + } } finally { stopWatch.stop(); if (log.isDebugEnabled()) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 51ac42f10..fb623dfd3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -108,10 +108,10 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { @Override public boolean isAutoStartup() { if (starterProperties.getEnableDlqMonitor() && starterProperties.getRpcMonitorStatus()) { - taskScheduler.scheduleWithFixedDelay(() -> mqWatch(BROADCAST), starterProperties.getDlqMonitorIntervalInMs()); + taskScheduler.scheduleWithFixedDelay(() -> mqWatch(RPC), starterProperties.getDlqMonitorIntervalInMs()); } if (starterProperties.getEnableDlqMonitor() && starterProperties.getBroadcast().getMonitorStatus()) { - taskScheduler.scheduleWithFixedDelay(() -> mqWatch(RPC), starterProperties.getDlqMonitorIntervalInMs()); + taskScheduler.scheduleWithFixedDelay(() -> mqWatch(BROADCAST), starterProperties.getDlqMonitorIntervalInMs()); } return false; } From 0892ed394bfe07d6f2dea539f3af5ab8d0f284d8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 17 Jun 2024 21:01:39 +0800 Subject: [PATCH 157/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E6=96=B0=E7=9A=84=E4=B8=80=E7=89=88=20ManageService?= =?UTF-8?q?=20=E6=8E=A5=E5=8F=A3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowManageService.java | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index cd89a0560..a7c8bbf59 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -215,6 +215,17 @@ public interface WorkflowManageService { @GetMapping("/api/process/model/tenant/ids") List getModelTenantIds(); + /** + * 创建审批流程并带上表单 + * + * @param dto + * @return + */ + @Operation(summary = "创建审批流程并带上表单") + @PostMapping("/api/process/instance/form/create") + @Manageable + String createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); + /** * 查询所有的审批流 * @@ -233,17 +244,6 @@ public interface WorkflowManageService { @Manageable BpmPageResult getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); - /** - * 创建审批流程并带上表单 - * - * @param dto - * @return - */ - @Operation(summary = "创建审批流程并带上表单") - @PostMapping("/api/process/instance/form/create") - @Manageable - String createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); - /** * 更新流程定义的状态 * @@ -468,6 +468,28 @@ public interface WorkflowManageService { @DeleteMapping("/api/process/variable/delete/{executionId}") Void deleteVariables(@PathVariable("executionId") String executionId, @RequestParam String variableNames, @RequestParam(value = "scope", required = false) String scope); + /** + * 催办 + * + * @param dto + * @return + */ + @Operation(summary = "审批流程催办") + @PostMapping("/api/process/task/remind") + @Manageable + Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); + + /** + * 添加附件 + * + * @param dto + * @return + */ + @Operation(summary = "添加附件") + @PostMapping("/api/process/task/attachment") + @Manageable + Void addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); + /** * 待审核列表 */ @@ -512,28 +534,6 @@ public interface WorkflowManageService { @Manageable List getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); - /** - * 添加附件 - * - * @param dto - * @return - */ - @Operation(summary = "添加附件") - @PostMapping("/api/process/task/attachment") - @Manageable - Void addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); - - /** - * 催办 - * - * @param dto - * @return - */ - @Operation(summary = "审批流程催办") - @PostMapping("/api/process/task/remind") - @Manageable - Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); - /** * 根据实例 ID 和自然人 ID 查询对应待处理的任务 ID * From 7319ab90adad2d3eff292d4de66c17cc56094ae8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 09:57:43 +0800 Subject: [PATCH 158/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E8=AE=B0=E5=BD=95=E6=8E=A5=E5=8F=A3=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RequestHeaderContextInterceptor.java | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java index d8c65b447..3ca7631bd 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.server.common.interceptor; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.repository.entity.ExtAxProperty; import cn.axzo.workflow.core.service.ExtAxPropertyService; +import cn.axzo.workflow.server.common.util.RedisUtils; import lombok.extern.slf4j.Slf4j; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.springframework.beans.factory.annotation.Autowired; @@ -12,8 +13,10 @@ import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.time.Duration; import java.util.Enumeration; import java.util.Objects; +import java.util.Optional; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; @@ -36,6 +39,8 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { private String serviceVersion; @Autowired private ExtAxPropertyService extAxPropertyService; + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + private static final String REPEAT_KEY = "global:api_application:"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { @@ -78,27 +83,47 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { if (!StringUtils.hasText(request.getHeader(HEADER_SERVER_NAME))) { return; } - ExtAxProperty property = extAxPropertyService.getByName(request.getHeader(HEADER_SERVER_NAME)).map(entity -> { - entity.setCreated(!Objects.equals(entity.getValue(), serviceVersion)); - entity.setValue(headerClientVersion); - return entity; - }).orElseGet(() -> { - ExtAxProperty extAxProperty = new ExtAxProperty(); - extAxProperty.setCreated(true); - extAxProperty.setName(request.getHeader(HEADER_SERVER_NAME)); - extAxProperty.setValue(clientVersion.toString()); - return extAxProperty; - }); - if (property.getCreated()) { - if (Objects.isNull(property.getId())) { - extAxPropertyService.add(property); - } else { - extAxPropertyService.update(property); - } + String requestApplicationName = request.getHeader(HEADER_SERVER_NAME); + Optional extAxProperty = extAxPropertyService.getByName(requestApplicationName); + String cacheRepeatKey = REPEAT_KEY + requestApplicationName; + log.info("repeatApi key: {}", cacheRepeatKey); + + String key = RedisUtils.getCacheObject(cacheRepeatKey); + if (Objects.isNull(key)) { + RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofSeconds(5)); + KEY_CACHE.set(cacheRepeatKey); + insert(extAxProperty, headerClientVersion, clientVersion); + } else { + update(extAxProperty, headerClientVersion, clientVersion); } } + private void update(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion) { + if (!extAxProperty.isPresent()) { + return; + } + ExtAxProperty property = extAxProperty.get(); + if (Objects.equals(property.getValue(), clientVersion.toString())) { + return; + } + property.setValue(clientVersion.toString()); + extAxPropertyService.update(property); + } + + private void insert(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion) { + if (extAxProperty.isPresent()) { + return; + } + extAxPropertyService.add(extAxProperty.orElseGet(() -> { + ExtAxProperty property = new ExtAxProperty(); + property.setCreated(true); + property.setName(requestApplicationName); + property.setValue(clientVersion.toString()); + return property; + })); + } + private void printHeader(HttpServletRequest request) { Enumeration headerNames = request.getHeaderNames(); log.info("parse header start, current uri: {}", request.getRequestURI()); From 49ee53626f0371a7df2974c6ff0e28bd621de526 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 10:29:32 +0800 Subject: [PATCH 159/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=BC=82=E5=B8=B8=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index aa9854aeb..aa47f3f3d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -11,6 +11,7 @@ import cn.axzo.framework.rocketmq.RocketMQEventProducer; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.api.WorkflowManageService; import cn.axzo.workflow.starter.common.condition.NonContainerEnvironmentCondition; +import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerFilterMQOwnerShip; import cn.axzo.workflow.starter.mq.broadcast.filter.InnerMessageQueueHandleBeforeFilter; import cn.axzo.workflow.starter.mq.retry.consumer.WorkflowEngineStarterRetryEventListener; @@ -141,7 +142,7 @@ public class StarterRPCInvokeMQConfiguration { return new EventHandlerRepository((ex, logText) -> { log.warn("MQ event handle repository has exception record: {}", logText, ex); if (Objects.nonNull(ex)) { - throw new RuntimeException(ex); + throw new WorkflowEngineStarterException(ex); } }); } From 15dec8b8a570b45bb779cabf86eef059a6a67bbe Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 10:44:23 +0800 Subject: [PATCH 160/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=9B=91=E6=8E=A7=20Controller=20=E7=B1=BB=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...kflowEngineStarterMQMonitorController.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index 733e17039..1f3f1e523 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -57,21 +57,37 @@ public class WorkflowEngineStarterMQMonitorController { } else { mqAdminExtObjectProvider.ifAvailable(defaultMQAdminExt -> { String segment = environment.getProperty(MQ_GID_NAME_SEGMENT); + String broadcastConsumer = String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment); + String rpcConsumer = String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment); try { - String broadcastConsumer = String.format(BROADCAST_CONSUMER_GROUP, applicationName, segment); - String rpcConsumer = String.format(RPC_RETRY_CONSUMER_GROUP, applicationName, segment); result.put("Engine Broadcast MQ", defaultMQAdminExt.examineConsumeStats(broadcastConsumer)); + } catch (Exception e) { + log.warn("monitor controller examineConsumeStats broadcast error: {}", e.getMessage(), e); + } + try { result.put("Starter RPC MQ", defaultMQAdminExt.examineConsumeStats(rpcConsumer)); - + } catch (Exception e) { + log.warn("monitor controller examineConsumeStats rpc error: {}", e.getMessage(), e); + } // result.put("BrokerClusterInfo", defaultMQAdminExt.examineBrokerClusterInfo()); // result.put("TopicClusterList", defaultMQAdminExt.getTopicClusterList(topic)); + try { result.put("TopicRouteInfo", defaultMQAdminExt.examineTopicRouteInfo(topic)); + } catch (Exception e) { + log.warn("monitor controller examineTopicRouteInfo error: {}", e.getMessage(), e); + } // result.put("TopicStats", defaultMQAdminExt.examineTopicStats(topic)); + try { result.put("Broadcast-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + broadcastConsumer)); + } catch (Exception e) { + log.warn("monitor controller examineTopicStats broadcast error: {}", e.getMessage(), e); + } + try { result.put("RPC-DLQ", defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + rpcConsumer)); } catch (Exception e) { - log.warn("monitor controller error: {}", e.getMessage(), e); + log.warn("monitor controller examineTopicStats rpc error: {}", e.getMessage(), e); } + }); } return CommonResponse.success(result); From b39f99fbb1909055865f3a766ec10d4fe88824a8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 11:01:16 +0800 Subject: [PATCH 161/210] =?UTF-8?q?update(REQ-2516)=20-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=8E=9F=20API=20=E5=8C=85=E7=9A=84=20FeignClient=20?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java | 2 +- .../axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java | 2 +- .../cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java | 2 +- .../java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java | 2 +- .../cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java | 2 +- .../java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java | 2 +- .../cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java | 2 +- .../axzo/workflow/client/feign/manage/ProcessCategoryApi.java | 2 +- .../cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 3f5fca64d..1f319c9c4 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -19,7 +19,7 @@ import javax.validation.constraints.NotBlank; * @author wangli * @since 2023/11/17 16:28 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessActivityApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java index a1bde7459..c588f7a72 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java @@ -24,7 +24,7 @@ import javax.validation.constraints.NotNull; * @author wangli * @since 2023/9/21 16:25 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) @Manageable public interface ProcessDefinitionApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index 84e761133..a8ff1b962 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -44,7 +44,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; * @author wangli * @since 2023/9/21 16:26 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessInstanceApi { /** * 创建审批流程 diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index f02ea2c9a..1ea91b95d 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -7,7 +7,7 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessJobApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index f3eca0f22..43bd3e428 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -29,7 +29,7 @@ import java.util.List; * @author wangli * @since 2023/9/21 15:47 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) @Manageable public interface ProcessModelApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 9cfd544b8..b73c36022 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -40,7 +40,7 @@ import java.util.Map; * @author wangli * @since 2023/9/21 16:26 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessTaskApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java index f9c88967d..63ef1992d 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java @@ -17,7 +17,7 @@ import javax.validation.constraints.NotBlank; /** * 流程变量api */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) @Manageable public interface ProcessVariableApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index 0536f56ed..1a6ba8ffd 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -32,7 +32,7 @@ import java.util.List; * @date 2023/11/6 16:01 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) @Manageable public interface ProcessCategoryApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java index b9727a802..a046d6262 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java @@ -18,7 +18,7 @@ import java.util.List; * @date 2023/11/6 16:01 */ -@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) @Manageable public interface ProcessConfigApi { From c49519fe8dfc6a97e5f93a7dad3cc24857ea40da Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 11:32:10 +0800 Subject: [PATCH 162/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=B0=86?= =?UTF-8?q?=E5=8F=97=E9=99=90=E8=AE=BF=E9=97=AE=E7=9A=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E9=83=BD=E8=AE=BE=E7=BD=AE=E4=B8=BA=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E8=B0=83=E7=94=A8=EF=BC=8C=E8=BF=99=E4=BA=9B=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=A4=A7=E5=A4=9A=E6=95=B0=E9=83=BD=E6=98=AF=E8=A6=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=BE=97=E5=88=B0=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/bpmn/ProcessDefinitionApi.java | 12 ++++ .../client/feign/bpmn/ProcessInstanceApi.java | 9 +++ .../client/feign/bpmn/ProcessJobApi.java | 3 + .../client/feign/bpmn/ProcessModelApi.java | 17 ++++++ .../client/feign/bpmn/ProcessTaskApi.java | 11 ++++ .../client/feign/bpmn/ProcessVariableApi.java | 6 ++ .../feign/manage/ProcessCategoryApi.java | 17 ++++++ .../client/feign/manage/ProcessConfigApi.java | 4 ++ .../starter/api/WorkflowManageService.java | 56 ++++++++++++++++++- 9 files changed, 134 insertions(+), 1 deletion(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java index c588f7a72..7a04b923a 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; @@ -18,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * 流程定义 API * @@ -33,6 +36,7 @@ public interface ProcessDefinitionApi { * 获取活跃的流程定义分页 */ @GetMapping("/api/process/definition/page") + @InvokeMode(SYNC) CommonResponse> getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto); /** @@ -42,6 +46,7 @@ public interface ProcessDefinitionApi { * @return */ @PutMapping("/api/process/definition/update") + @InvokeMode(SYNC) CommonResponse updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto); /** @@ -51,6 +56,7 @@ public interface ProcessDefinitionApi { * @return 流程定义 */ @GetMapping("/api/process/definition/get") + @InvokeMode(SYNC) CommonResponse getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId); /** @@ -60,6 +66,7 @@ public interface ProcessDefinitionApi { * @return 流程定义 */ @GetMapping("/api/process/definition/getByDeploymentId") + @InvokeMode(SYNC) CommonResponse getProcessDefinitionByDeploymentId( @NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId); @@ -71,6 +78,7 @@ public interface ProcessDefinitionApi { * @return 流程定义 */ @GetMapping("/api/process/definition/active/getByKey") + @InvokeMode(SYNC) CommonResponse getActiveProcessDefinitionByKey(@NotBlank(message = "模型定义KEY不能为空") @RequestParam String key); @@ -81,6 +89,7 @@ public interface ProcessDefinitionApi { * {@see SuspensionState} */ @PutMapping("/api/process/definition/state/update") + @InvokeMode(SYNC) CommonResponse getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer state); @@ -90,6 +99,7 @@ public interface ProcessDefinitionApi { * @return 流程定义ID */ @GetMapping("/api/process/definition/active/getByCategory") + @InvokeMode(SYNC) CommonResponse getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category); @@ -99,6 +109,7 @@ public interface ProcessDefinitionApi { * @return 流程定义ID */ @GetMapping("/api/process/definition/active/json/model") + @InvokeMode(SYNC) CommonResponse getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category, @RequestParam(required = false) String tenantId); @@ -111,6 +122,7 @@ public interface ProcessDefinitionApi { * @return */ @GetMapping("/api/process/definition/delete") + @InvokeMode(SYNC) CommonResponse delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId, @RequestParam(required = false) Boolean cascade); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index a8ff1b962..06860f5f8 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -140,6 +140,7 @@ public interface ProcessInstanceApi { @Operation(summary = "创建审批流程并带上表单") @PostMapping("/api/process/instance/form/create") @Manageable + @InvokeMode(SYNC) CommonResponse createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); /** @@ -150,6 +151,7 @@ public interface ProcessInstanceApi { @Operation(summary = "查询所有的审批流") @PostMapping("/api/process/instance/page/all") @Manageable + @InvokeMode(SYNC) CommonResponse> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); /** @@ -158,6 +160,7 @@ public interface ProcessInstanceApi { @Operation(summary = "我发起的审批列表") @PostMapping("/api/process/instance/page/my") @Manageable + @InvokeMode(SYNC) CommonResponse> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); /** @@ -169,6 +172,7 @@ public interface ProcessInstanceApi { @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例") @PutMapping("/api/process/instance/status/update") @Manageable + @InvokeMode(SYNC) CommonResponse updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status); @@ -182,6 +186,7 @@ public interface ProcessInstanceApi { @Operation(summary = "获取审批流程实例的运行图") @GetMapping("/api/process/instance/graphical") @Manageable + @InvokeMode(SYNC) CommonResponse processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -193,6 +198,7 @@ public interface ProcessInstanceApi { @Operation(summary = "推断指定流程实例的所有节点执行顺序") @GetMapping("/api/process/instance/node/forecasting") @Manageable + @InvokeMode(SYNC) CommonResponse> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -206,6 +212,7 @@ public interface ProcessInstanceApi { @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") @GetMapping("/api/process/instance/node/filter/forecasting") @Manageable + @InvokeMode(SYNC) CommonResponse> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @@ -219,6 +226,7 @@ public interface ProcessInstanceApi { @Operation(summary = "查询实例的租户集合") @GetMapping("/api/process/instance/tenant/ids") @Manageable + @InvokeMode(SYNC) CommonResponse> getTenantIds(); /** @@ -229,5 +237,6 @@ public interface ProcessInstanceApi { @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") @PostMapping("/api/process/instance/check/approver") @Manageable + @InvokeMode(SYNC) CommonResponse checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index 1ea91b95d..906bbc1f3 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -1,12 +1,15 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.azxo.framework.common.model.CommonResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) public interface ProcessJobApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index 43bd3e428..8fc7f7f00 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; @@ -23,6 +24,8 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.List; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * 流程模型 API * @@ -41,6 +44,7 @@ public interface ProcessModelApi { */ @Operation(summary = "流程模型列表") @GetMapping("/api/process/model/page") + @InvokeMode(SYNC) CommonResponse> page(@Validated @RequestBody BpmnModelSearchDTO dto); /** @@ -49,6 +53,7 @@ public interface ProcessModelApi { */ @Operation(summary = "创建流程模型") @PostMapping("/api/process/model/create") + @InvokeMode(SYNC) CommonResponse create(@Validated @RequestBody BpmnModelCreateDTO dto); /** @@ -56,6 +61,7 @@ public interface ProcessModelApi { */ @Operation(summary = "通过模型ID查询指定流程模型") @GetMapping("/api/process/model/get") + @InvokeMode(SYNC) CommonResponse getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false) String tenantId); @@ -64,6 +70,7 @@ public interface ProcessModelApi { */ @Operation(summary = "通过模型KEY查询指定流程模型") @GetMapping("/api/process/model/getByKey") + @InvokeMode(SYNC) CommonResponse getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId); @@ -76,6 +83,7 @@ public interface ProcessModelApi { */ @Operation(summary = "获取指定模型的扩展属性") @GetMapping("/api/process/model/ext") + @InvokeMode(SYNC) CommonResponse getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId); /** @@ -83,6 +91,7 @@ public interface ProcessModelApi { */ @Operation(summary = "更新流程模型") @PutMapping("/api/process/model/update") + @InvokeMode(SYNC) CommonResponse update(@RequestBody BpmnModelUpdateDTO dto); @@ -93,6 +102,7 @@ public interface ProcessModelApi { */ @Operation(summary = "通过模型 ID 部署流程模型") @PostMapping("/api/process/model/deploy") + @InvokeMode(SYNC) CommonResponse deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String modelTenantId, @RequestParam(required = false) String operator); @@ -104,6 +114,7 @@ public interface ProcessModelApi { */ @Operation(summary = "通过模型 KEY 部署流程模型") @PostMapping("/api/process/model/deployByKey") + @InvokeMode(SYNC) CommonResponse deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId, @RequestParam(required = false) String operator); @@ -118,6 +129,7 @@ public interface ProcessModelApi { */ @Operation(summary = "通过模型 ID 取消部署流程模型") @PostMapping("/api/process/model/undeploy") + @InvokeMode(SYNC) CommonResponse unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId, @RequestParam(required = false) String operator); @@ -127,6 +139,7 @@ public interface ProcessModelApi { */ @Operation(summary = "删除指定模型 ID 的流程模型") @DeleteMapping("/api/process/model/delete") + @InvokeMode(SYNC) CommonResponse deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId); @@ -139,6 +152,7 @@ public interface ProcessModelApi { */ @Operation(summary = "删除指定模型 KEY 的流程模型") @DeleteMapping("/api/process/model/deleteByKey") + @InvokeMode(SYNC) CommonResponse deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey, @RequestParam(required = false, defaultValue = "") String tenantId); @@ -152,6 +166,7 @@ public interface ProcessModelApi { */ @Operation(summary = "修改模型状态") @PostMapping("/api/process/model/changeStatus") + @InvokeMode(SYNC) CommonResponse changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId, @NotNull(message = "状态不能为空") @RequestParam Integer status, @RequestParam(required = false) String operator); @@ -163,6 +178,7 @@ public interface ProcessModelApi { */ @Operation(summary = "查询流程模型使用的分类列表") @GetMapping("/api/process/model/category/ids") + @InvokeMode(SYNC) CommonResponse> getModelCategoryList(); /** @@ -172,5 +188,6 @@ public interface ProcessModelApi { */ @Operation(summary = "查询模型的租户集合") @GetMapping("/api/process/model/tenant/ids") + @InvokeMode(SYNC) CommonResponse> getModelTenantIds(); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index b73c36022..80d57d980 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; @@ -33,6 +34,8 @@ import javax.validation.constraints.NotEmpty; import java.util.List; import java.util.Map; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * 流程任务 API @@ -139,6 +142,7 @@ public interface ProcessTaskApi { @Operation(summary = "审批流程催办") @PostMapping("/api/process/task/remind") @Manageable + @InvokeMode(SYNC) CommonResponse remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); /** @@ -178,6 +182,7 @@ public interface ProcessTaskApi { @Operation(summary = "待审核列表") @GetMapping("/api/process/task/page/todo") @Manageable + @InvokeMode(SYNC) CommonResponse> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** @@ -186,6 +191,7 @@ public interface ProcessTaskApi { @Operation(summary = "已完成的审批列表") @GetMapping("/api/process/task/page/done") @Manageable + @InvokeMode(SYNC) CommonResponse> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** @@ -196,6 +202,7 @@ public interface ProcessTaskApi { @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/flat") @Manageable + @InvokeMode(SYNC) CommonResponse> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -207,6 +214,7 @@ public interface ProcessTaskApi { @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/group") @Manageable + @InvokeMode(SYNC) CommonResponse> getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); @@ -216,6 +224,7 @@ public interface ProcessTaskApi { @Operation(summary = "获取实例正在审核的人列表") @GetMapping("/api/process/task/active/list") @Manageable + @InvokeMode(SYNC) CommonResponse> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); @@ -227,6 +236,7 @@ public interface ProcessTaskApi { @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/find") @Manageable + @InvokeMode(SYNC) CommonResponse findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); @@ -238,6 +248,7 @@ public interface ProcessTaskApi { @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/batch/find") @Manageable + @InvokeMode(SYNC) CommonResponse> findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java index 63ef1992d..2c219f88b 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.azxo.framework.common.model.CommonResponse; @@ -14,6 +15,8 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.validation.constraints.NotBlank; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * 流程变量api */ @@ -25,6 +28,7 @@ public interface ProcessVariableApi { * 为指定流程新增变量 */ @PostMapping("/api/process/variable/create/{executionId}") + @InvokeMode(SYNC) CommonResponse createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); @@ -36,6 +40,7 @@ public interface ProcessVariableApi { * @return */ @PostMapping("/api/process/variable/update/{executionId}") + @InvokeMode(SYNC) CommonResponse updateVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); @@ -43,6 +48,7 @@ public interface ProcessVariableApi { * 批量删除流程变量 */ @DeleteMapping("/api/process/variable/delete/{executionId}") + @InvokeMode(SYNC) CommonResponse deleteVariables(@PathVariable("executionId") String executionId, @RequestParam String variableNames, @RequestParam(value = "scope", required = false) String scope); diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index 1a6ba8ffd..aa1d51447 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.manage; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; @@ -23,6 +24,8 @@ import org.springframework.web.bind.annotation.RequestParam; import java.util.List; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * OMS流程业务管理API @@ -42,6 +45,7 @@ public interface ProcessCategoryApi { * @return */ @GetMapping("/api/process/category/get") + @InvokeMode(SYNC) CommonResponse get(@RequestParam Long id); /** @@ -51,6 +55,7 @@ public interface ProcessCategoryApi { * @return */ @GetMapping("/api/process/category/getByIds") + @InvokeMode(SYNC) CommonResponse> getByIds(@RequestParam List ids); /** @@ -60,6 +65,7 @@ public interface ProcessCategoryApi { * @return */ @GetMapping("/api/process/category/getByValues") + @InvokeMode(SYNC) CommonResponse> getByValues(@RequestParam List values); /** @@ -68,6 +74,7 @@ public interface ProcessCategoryApi { * @return */ @PostMapping("/api/process/category/create") + @InvokeMode(SYNC) CommonResponse create(@Validated @RequestBody CategoryCreateDTO req); /** @@ -76,6 +83,7 @@ public interface ProcessCategoryApi { * @return */ @PutMapping("/api/process/category/update") + @InvokeMode(SYNC) CommonResponse update(@Validated @RequestBody CategoryUpdateDTO dto); /** @@ -85,6 +93,7 @@ public interface ProcessCategoryApi { * @return */ @DeleteMapping("/api/process/category/delete") + @InvokeMode(SYNC) CommonResponse delete(@RequestParam Long id); /** @@ -95,6 +104,7 @@ public interface ProcessCategoryApi { * @return */ @PutMapping("/api/process/category/update/state") + @InvokeMode(SYNC) CommonResponse updateState(@RequestParam Long id, @RequestParam Boolean state); /** @@ -103,6 +113,7 @@ public interface ProcessCategoryApi { * @return */ @PostMapping("/api/process/category/list") + @InvokeMode(SYNC) CommonResponse> list(@RequestBody CategorySearchDTO dto); /** @@ -111,6 +122,7 @@ public interface ProcessCategoryApi { * @return */ @PostMapping("/api/process/category/page/search") + @InvokeMode(SYNC) CommonResponse> search(@RequestBody CategorySearchDTO dto); /** @@ -120,6 +132,7 @@ public interface ProcessCategoryApi { * @return */ @PostMapping("/api/process/category/config/create") + @InvokeMode(SYNC) CommonResponse createConfig(@RequestBody CategoryConfigCreateDTO dto); /** @@ -129,6 +142,7 @@ public interface ProcessCategoryApi { * @return */ @DeleteMapping("/api/process/category/config/delete/{id}") + @InvokeMode(SYNC) CommonResponse deleteConfig(@PathVariable Long id); /** @@ -137,6 +151,7 @@ public interface ProcessCategoryApi { * @return */ @PostMapping("/api/process/category/config/page/search") + @InvokeMode(SYNC) CommonResponse> configSearch(@RequestBody CategoryConfigSearchDTO dto); /** @@ -147,6 +162,7 @@ public interface ProcessCategoryApi { * @return */ @PostMapping("/api/process/category/config/type/update") + @InvokeMode(SYNC) CommonResponse updateCategoryConfigType(@RequestParam Long id, @RequestParam String configType); /** @@ -157,5 +173,6 @@ public interface ProcessCategoryApi { * @return true: 可以发起创建流程实例, false: 不可用 */ @GetMapping("/api/process/category/check/status") + @InvokeMode(SYNC) CommonResponse checkCategoryStatus(@RequestParam Long tenantId, @RequestParam String categoryCode); } diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java index a046d6262..5f56d5d64 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.manage; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.azxo.framework.common.model.CommonResponse; @@ -9,6 +10,8 @@ import org.springframework.web.bind.annotation.GetMapping; import java.util.List; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; + /** * OMS流程业务管理API @@ -28,6 +31,7 @@ public interface ProcessConfigApi { * @return 流程操作按钮列表 */ @GetMapping("/api/process/config/button/list") + @InvokeMode(SYNC) CommonResponse> getDefaultButtons(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index a7c8bbf59..7f8a7d548 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.util.ThreadUtil; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.azxo.framework.common.model.CommonResponse; @@ -27,7 +28,6 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; @@ -85,6 +85,7 @@ public interface WorkflowManageService { * @return 流程操作按钮列表 */ @GetMapping("/api/process/config/button/list") + @InvokeMode(SYNC) List getDefaultButtons(); /** @@ -95,6 +96,7 @@ public interface WorkflowManageService { */ @Operation(summary = "流程模型列表") @GetMapping("/api/process/model/page") + @InvokeMode(SYNC) BpmPageResult page(@Validated @RequestBody BpmnModelSearchDTO dto); /** @@ -103,6 +105,7 @@ public interface WorkflowManageService { */ @Operation(summary = "创建流程模型") @PostMapping("/api/process/model/create") + @InvokeMode(SYNC) String create(@Validated @RequestBody BpmnModelCreateDTO dto); /** @@ -110,6 +113,7 @@ public interface WorkflowManageService { */ @Operation(summary = "通过模型ID查询指定流程模型") @GetMapping("/api/process/model/get") + @InvokeMode(SYNC) BpmnModelDetailVO getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false) String tenantId); /** @@ -117,6 +121,7 @@ public interface WorkflowManageService { */ @Operation(summary = "通过模型KEY查询指定流程模型") @GetMapping("/api/process/model/getByKey") + @InvokeMode(SYNC) BpmnModelDetailVO getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId); /** @@ -128,6 +133,7 @@ public interface WorkflowManageService { */ @Operation(summary = "获取指定模型的扩展属性") @GetMapping("/api/process/model/ext") + @InvokeMode(SYNC) BpmnModelExtVO getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId); /** @@ -135,6 +141,7 @@ public interface WorkflowManageService { */ @Operation(summary = "更新流程模型") @PutMapping("/api/process/model/update") + @InvokeMode(SYNC) String update(@RequestBody BpmnModelUpdateDTO dto); /** @@ -144,6 +151,7 @@ public interface WorkflowManageService { */ @Operation(summary = "通过模型 ID 部署流程模型") @PostMapping("/api/process/model/deploy") + @InvokeMode(SYNC) String deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String modelTenantId, @RequestParam(required = false) String operator); /** @@ -153,6 +161,7 @@ public interface WorkflowManageService { */ @Operation(summary = "通过模型 KEY 部署流程模型") @PostMapping("/api/process/model/deployByKey") + @InvokeMode(SYNC) String deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId, @RequestParam(required = false) String operator); /** @@ -165,6 +174,7 @@ public interface WorkflowManageService { */ @Operation(summary = "通过模型 ID 取消部署流程模型") @PostMapping("/api/process/model/undeploy") + @InvokeMode(SYNC) Void unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId, @RequestParam(required = false) String operator); /** @@ -172,6 +182,7 @@ public interface WorkflowManageService { */ @Operation(summary = "删除指定模型 ID 的流程模型") @DeleteMapping("/api/process/model/delete") + @InvokeMode(SYNC) Void deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId); /** @@ -183,6 +194,7 @@ public interface WorkflowManageService { */ @Operation(summary = "删除指定模型 KEY 的流程模型") @DeleteMapping("/api/process/model/deleteByKey") + @InvokeMode(SYNC) Void deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey, @RequestParam(required = false, defaultValue = "") String tenantId); /** @@ -195,6 +207,7 @@ public interface WorkflowManageService { */ @Operation(summary = "修改模型状态") @PostMapping("/api/process/model/changeStatus") + @InvokeMode(SYNC) Void changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId, @NotNull(message = "状态不能为空") @RequestParam Integer status, @RequestParam(required = false) String operator); /** @@ -204,6 +217,7 @@ public interface WorkflowManageService { */ @Operation(summary = "查询流程模型使用的分类列表") @GetMapping("/api/process/model/category/ids") + @InvokeMode(SYNC) List getModelCategoryList(); /** @@ -213,6 +227,7 @@ public interface WorkflowManageService { */ @Operation(summary = "查询模型的租户集合") @GetMapping("/api/process/model/tenant/ids") + @InvokeMode(SYNC) List getModelTenantIds(); /** @@ -234,6 +249,7 @@ public interface WorkflowManageService { @Operation(summary = "查询所有的审批流") @PostMapping("/api/process/instance/page/all") @Manageable + @InvokeMode(SYNC) BpmPageResult getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); /** @@ -242,6 +258,7 @@ public interface WorkflowManageService { @Operation(summary = "我发起的审批列表") @PostMapping("/api/process/instance/page/my") @Manageable + @InvokeMode(SYNC) BpmPageResult getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); /** @@ -253,6 +270,7 @@ public interface WorkflowManageService { @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例") @PutMapping("/api/process/instance/status/update") @Manageable + @InvokeMode(SYNC) Boolean updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status); /** @@ -265,6 +283,7 @@ public interface WorkflowManageService { @Operation(summary = "获取审批流程实例的运行图") @GetMapping("/api/process/instance/graphical") @Manageable + @InvokeMode(SYNC) ObjectNode processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** @@ -275,6 +294,7 @@ public interface WorkflowManageService { @Operation(summary = "推断指定流程实例的所有节点执行顺序") @GetMapping("/api/process/instance/node/forecasting") @Manageable + @InvokeMode(SYNC) List processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** @@ -287,6 +307,7 @@ public interface WorkflowManageService { @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") @GetMapping("/api/process/instance/node/filter/forecasting") @Manageable + @InvokeMode(SYNC) List processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @Nullable @RequestParam(required = false) List nodeDefinitionKeys); /** @@ -297,6 +318,7 @@ public interface WorkflowManageService { @Operation(summary = "查询实例的租户集合") @GetMapping("/api/process/instance/tenant/ids") @Manageable + @InvokeMode(SYNC) List getTenantIds(); /** @@ -307,6 +329,7 @@ public interface WorkflowManageService { @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") @PostMapping("/api/process/instance/check/approver") @Manageable + @InvokeMode(SYNC) Boolean checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); /** @@ -329,6 +352,7 @@ public interface WorkflowManageService { * @return */ @GetMapping("/api/process/category/get") + @InvokeMode(SYNC) CategoryItemVO get(@RequestParam Long id); /** @@ -338,6 +362,7 @@ public interface WorkflowManageService { * @return */ @GetMapping("/api/process/category/getByIds") + @InvokeMode(SYNC) List getByIds(@RequestParam List ids); /** @@ -347,6 +372,7 @@ public interface WorkflowManageService { * @return */ @GetMapping("/api/process/category/getByValues") + @InvokeMode(SYNC) List getByValues(@RequestParam List values); /** @@ -355,6 +381,7 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/category/create") + @InvokeMode(SYNC) CategoryItemVO create(@Validated @RequestBody CategoryCreateDTO req); /** @@ -363,6 +390,7 @@ public interface WorkflowManageService { * @return */ @PutMapping("/api/process/category/update") + @InvokeMode(SYNC) CategoryItemVO update(@Validated @RequestBody CategoryUpdateDTO dto); /** @@ -372,6 +400,7 @@ public interface WorkflowManageService { * @return */ @DeleteMapping("/api/process/category/delete") + @InvokeMode(SYNC) Boolean delete(@RequestParam Long id); /** @@ -382,6 +411,7 @@ public interface WorkflowManageService { * @return */ @PutMapping("/api/process/category/update/state") + @InvokeMode(SYNC) Boolean updateState(@RequestParam Long id, @RequestParam Boolean state); /** @@ -390,6 +420,7 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/category/list") + @InvokeMode(SYNC) List list(@RequestBody CategorySearchDTO dto); /** @@ -398,6 +429,7 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/category/page/search") + @InvokeMode(SYNC) BpmPageResult search(@RequestBody CategorySearchDTO dto); /** @@ -407,6 +439,7 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/category/config/create") + @InvokeMode(SYNC) Boolean createConfig(@RequestBody CategoryConfigCreateDTO dto); /** @@ -416,6 +449,7 @@ public interface WorkflowManageService { * @return */ @DeleteMapping("/api/process/category/config/delete/{id}") + @InvokeMode(SYNC) Boolean deleteConfig(@PathVariable Long id); /** @@ -424,6 +458,7 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/category/config/page/search") + @InvokeMode(SYNC) BpmPageResult configSearch(@RequestBody CategoryConfigSearchDTO dto); /** @@ -434,6 +469,7 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/category/config/type/update") + @InvokeMode(SYNC) Boolean updateCategoryConfigType(@RequestParam Long id, @RequestParam String configType); /** @@ -444,6 +480,7 @@ public interface WorkflowManageService { * @return true: 可以发起创建流程实例, false: 不可用 */ @GetMapping("/api/process/category/check/status") + @InvokeMode(SYNC) Boolean checkCategoryStatus(@RequestParam Long tenantId, @RequestParam String categoryCode); /** @@ -477,6 +514,7 @@ public interface WorkflowManageService { @Operation(summary = "审批流程催办") @PostMapping("/api/process/task/remind") @Manageable + @InvokeMode(SYNC) Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); /** @@ -496,6 +534,7 @@ public interface WorkflowManageService { @Operation(summary = "待审核列表") @GetMapping("/api/process/task/page/todo") @Manageable + @InvokeMode(SYNC) BpmPageResult getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** @@ -504,6 +543,7 @@ public interface WorkflowManageService { @Operation(summary = "已完成的审批列表") @GetMapping("/api/process/task/page/done") @Manageable + @InvokeMode(SYNC) BpmPageResult getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); /** @@ -514,6 +554,7 @@ public interface WorkflowManageService { @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/flat") @Manageable + @InvokeMode(SYNC) List getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** @@ -524,6 +565,7 @@ public interface WorkflowManageService { @Operation(summary = "获取指定流程实例的审批过程信息") @GetMapping("/api/process/task/list/group") @Manageable + @InvokeMode(SYNC) List getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** @@ -532,6 +574,7 @@ public interface WorkflowManageService { @Operation(summary = "获取实例正在审核的人列表") @GetMapping("/api/process/task/active/list") @Manageable + @InvokeMode(SYNC) List getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); /** @@ -542,6 +585,7 @@ public interface WorkflowManageService { @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/find") @Manageable + @InvokeMode(SYNC) String findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); /** @@ -552,12 +596,14 @@ public interface WorkflowManageService { @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") @GetMapping("/api/process/task/batch/find") @Manageable + @InvokeMode(SYNC) Map findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); /** * 获取活跃的流程定义分页 */ @GetMapping("/api/process/definition/page") + @InvokeMode(SYNC) BpmPageResult getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto); /** @@ -567,6 +613,7 @@ public interface WorkflowManageService { * @return */ @PutMapping("/api/process/definition/update") + @InvokeMode(SYNC) Boolean updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto); /** @@ -576,6 +623,7 @@ public interface WorkflowManageService { * @return 流程定义 */ @GetMapping("/api/process/definition/get") + @InvokeMode(SYNC) BpmnProcessDefinitionVO getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId); /** @@ -585,6 +633,7 @@ public interface WorkflowManageService { * @return 流程定义 */ @GetMapping("/api/process/definition/getByDeploymentId") + @InvokeMode(SYNC) BpmnProcessDefinitionVO getProcessDefinitionByDeploymentId(@NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId); /** @@ -594,6 +643,7 @@ public interface WorkflowManageService { * @return 流程定义 */ @GetMapping("/api/process/definition/active/getByKey") + @InvokeMode(SYNC) BpmnProcessDefinitionVO getActiveProcessDefinitionByKey(@NotBlank(message = "模型定义KEY不能为空") @RequestParam String key); /** @@ -603,6 +653,7 @@ public interface WorkflowManageService { * {@see SuspensionState} */ @PutMapping("/api/process/definition/state/update") + @InvokeMode(SYNC) Boolean getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer state); /** @@ -611,6 +662,7 @@ public interface WorkflowManageService { * @return 流程定义ID */ @GetMapping("/api/process/definition/active/getByCategory") + @InvokeMode(SYNC) String getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category); /** @@ -619,6 +671,7 @@ public interface WorkflowManageService { * @return 流程定义ID */ @GetMapping("/api/process/definition/active/json/model") + @InvokeMode(SYNC) BpmnModelUpdateDTO getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category, @RequestParam(required = false) String tenantId); /** @@ -629,6 +682,7 @@ public interface WorkflowManageService { * @return */ @GetMapping("/api/process/definition/delete") + @InvokeMode(SYNC) Void delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId, @RequestParam(required = false) Boolean cascade); /** From ed32d6020c7be9808bd95083b3115bcc96cfe806 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 14:09:10 +0800 Subject: [PATCH 163/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=B0=86?= =?UTF-8?q?=E5=8F=97=E9=99=90=E8=AE=BF=E9=97=AE=E7=9A=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E9=83=BD=E8=AE=BE=E7=BD=AE=E4=B8=BA=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E8=B0=83=E7=94=A8=EF=BC=8C=E8=BF=99=E4=BA=9B=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=A4=A7=E5=A4=9A=E6=95=B0=E9=83=BD=E6=98=AF=E8=A6=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=BE=97=E5=88=B0=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessModelServiceImpl.java | 2 +- .../starter/feign/ext/WorkflowEngineStarterDecoder.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java index e48bf26e2..680eb9ef1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java @@ -455,7 +455,7 @@ public class BpmnProcessModelServiceImpl implements BpmnProcessModelService { if (CollectionUtils.isEmpty(list)) { return Collections.emptyList(); } - return list.stream().map(Model::getTenantId).collect(Collectors.toList()); + return list.stream().map(Model::getTenantId).distinct().collect(Collectors.toList()); } private void updateProcessDefinitionSuspended(String deploymentId) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 4dae9b073..065696f47 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -12,6 +12,7 @@ import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; @@ -61,7 +62,7 @@ final class WorkflowEngineStarterDecoder implements Decoder { */ Object convert(Response response, Type type) throws IOException { ParameterizedTypeImpl wrappedType; - List> cls = Lists.newArrayList(List.class, Map.class); + List> cls = Lists.newArrayList(Collection.class, List.class, Map.class); if (type instanceof ParameterizedType && !cls.contains(((ParameterizedType) type).getRawType())) { wrappedType = (ParameterizedTypeImpl) type; } else { @@ -71,7 +72,7 @@ final class WorkflowEngineStarterDecoder implements Decoder { if (decode instanceof CommonResponse) { CommonResponse commonResponse = (CommonResponse) decode; if (response.status() == 202) { - log.warn("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg()); + log.error("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg()); } return commonResponse.getData(); } From 89e390f102eafde8bc2c551645819c073021a475 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 15:00:41 +0800 Subject: [PATCH 164/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20ComplexInvokeClient=20=E7=9A=84=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowManageService.java | 4 ++++ .../exception/WorkflowRpcInvokeException.java | 21 +++++++++++++++++++ .../ext/WorkflowEngineStarterDecoder.java | 7 ++++++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRpcInvokeException.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 7f8a7d548..78809f2da 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -239,6 +239,7 @@ public interface WorkflowManageService { @Operation(summary = "创建审批流程并带上表单") @PostMapping("/api/process/instance/form/create") @Manageable + @InvokeMode(SYNC) String createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); /** @@ -487,6 +488,7 @@ public interface WorkflowManageService { * 为指定流程新增变量 */ @PostMapping("/api/process/variable/create/{executionId}") + @InvokeMode(SYNC) Void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); /** @@ -497,12 +499,14 @@ public interface WorkflowManageService { * @return */ @PostMapping("/api/process/variable/update/{executionId}") + @InvokeMode(SYNC) Void updateVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); /** * 批量删除流程变量 */ @DeleteMapping("/api/process/variable/delete/{executionId}") + @InvokeMode(SYNC) Void deleteVariables(@PathVariable("executionId") String executionId, @RequestParam String variableNames, @RequestParam(value = "scope", required = false) String scope); /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRpcInvokeException.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRpcInvokeException.java new file mode 100644 index 000000000..4ffde34dc --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/exception/WorkflowRpcInvokeException.java @@ -0,0 +1,21 @@ +package cn.axzo.workflow.starter.common.exception; + +/** + * Starter 的 RPC 动作调用异常 + * + * @author wangli + * @since 2024/6/18 14:20 + */ +public class WorkflowRpcInvokeException extends WorkflowEngineStarterException { + public WorkflowRpcInvokeException(Throwable cause) { + super(cause); + } + + public WorkflowRpcInvokeException(String message) { + super(message); + } + + public WorkflowRpcInvokeException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 065696f47..78cf7d339 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -1,5 +1,7 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; +import cn.axzo.workflow.starter.common.exception.WorkflowRpcInvokeException; import cn.azxo.framework.common.model.CommonResponse; import com.google.common.collect.Lists; import feign.Response; @@ -72,7 +74,10 @@ final class WorkflowEngineStarterDecoder implements Decoder { if (decode instanceof CommonResponse) { CommonResponse commonResponse = (CommonResponse) decode; if (response.status() == 202) { - log.error("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg()); + log.warn("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg()); + throw new WorkflowRpcInvokeException(commonResponse.getMsg()); + } else { + log.error("WorkflowEngineStarterDecoder has error, status:{} msg: {}", response.status(), commonResponse.getMsg()); } return commonResponse.getData(); } From d278f3903c4cc5aa01d43af6722fa9984e2a2d16 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 15:59:51 +0800 Subject: [PATCH 165/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20ComplexInvokeClient=20=E7=9A=84=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/feign/ext/WorkflowEngineStarterDecoder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 78cf7d339..4575c2032 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.common.exception.WorkflowRpcInvokeException; import cn.azxo.framework.common.model.CommonResponse; @@ -64,7 +65,7 @@ final class WorkflowEngineStarterDecoder implements Decoder { */ Object convert(Response response, Type type) throws IOException { ParameterizedTypeImpl wrappedType; - List> cls = Lists.newArrayList(Collection.class, List.class, Map.class); + List> cls = Lists.newArrayList(BpmPageResult.class, Collection.class, List.class, Map.class); if (type instanceof ParameterizedType && !cls.contains(((ParameterizedType) type).getRawType())) { wrappedType = (ParameterizedTypeImpl) type; } else { From bd1d8dcdf5175343eb2dc51d4b1bddad82a18aaf Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 16:40:21 +0800 Subject: [PATCH 166/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E9=83=A8=E5=88=86=E6=8E=A5=E5=8F=A3=E7=9A=84=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index 06860f5f8..e2368600f 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -117,6 +117,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "获得流程实例") @GetMapping("/api/process/instance/get") + @InvokeMode(SYNC) CommonResponse getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); /** @@ -128,6 +129,7 @@ public interface ProcessInstanceApi { */ @Operation(summary = "获取指定流程实例的流程变量") @GetMapping("/api/process/instance/cooperation-org") + @InvokeMode(SYNC) CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); From e1e4d11da65b9c72446e6963a24ecce27edc5a69 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 16:44:02 +0800 Subject: [PATCH 167/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20MQ=20admin=20=E7=9A=84=20instanceName?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/WorkflowEngineStarterAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index e13b58eb2..232c50771 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -123,7 +123,7 @@ public class WorkflowEngineStarterAutoConfiguration { throw new RuntimeException("Build DefaultMQAdminExt error, namesrv is null", null); } DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt((RPCHook) null, 5000L); - defaultMQAdminExt.setInstanceName("admin-" + System.currentTimeMillis()); + defaultMQAdminExt.setInstanceName("workflow-engine-starter-" + System.currentTimeMillis()); defaultMQAdminExt.setNamesrvAddr(namesrvAddress); try { defaultMQAdminExt.start(); From d4ad35e523613889859d86c8d7e8805efc331c50 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 17:29:38 +0800 Subject: [PATCH 168/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=86=85=E7=BD=AE=E7=9A=84=E6=8E=A5=E5=8F=A3=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 2 ++ ...orkflowEngineStarterInvocationHandler.java | 23 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 67ce136d0..f7d7aefdf 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -154,6 +154,7 @@ public interface WorkflowCoreService { */ @Operation(summary = "获得流程实例") @GetMapping("/api/process/instance/get") + @InvokeMode(SYNC) BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); /** @@ -165,6 +166,7 @@ public interface WorkflowCoreService { */ @Operation(summary = "获取指定流程实例的流程变量") @GetMapping("/api/process/instance/cooperation-org") + @InvokeMode(SYNC) Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java index 57472159b..a3c4ba593 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -2,13 +2,19 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.util.ThreadUtil; +import com.alibaba.fastjson.JSON; +import com.google.common.collect.Lists; import feign.InvocationHandlerFactory; import feign.Target; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.util.StopWatch; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -20,6 +26,7 @@ import java.util.Objects; */ class WorkflowEngineStarterInvocationHandler implements InvocationHandler { + private static final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterInvocationHandler.class); private final Target target; private final Map dispatch; @@ -45,8 +52,20 @@ class WorkflowEngineStarterInvocationHandler implements InvocationHandler { } parseInvokeModelAnnotation(method); - - return dispatch.get(method).invoke(args); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(method.getName()); + Object invoke = null; + try { + invoke = dispatch.get(method).invoke(args); + } finally { + stopWatch.stop(); + List ignoreMethods = Lists.newArrayList("sync", "async"); + if (!ignoreMethods.contains(method.getName())) { + log.info("Workflow starter Method invoke record: {}.{}, args: {}, result: {} const: {} ms", + target.type().getSimpleName(), method.getName(), JSON.toJSONString(args), JSON.toJSONString(invoke), stopWatch.getTotalTimeMillis()); + } + } + return invoke; } private void parseInvokeModelAnnotation(Method method) { From 3843ad858411cafcad3fc90d4f1eb3c45ab4141e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 18:17:28 +0800 Subject: [PATCH 169/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E5=B8=B8=E9=87=8F=E7=B1=BB=E8=B7=AF=E5=BE=84=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E8=AE=B0=E5=BD=95=E6=8E=A5=E5=85=A5=E6=96=B9=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E6=9C=89=E5=BC=80=E5=90=AF=20manageable=20=E5=B1=9E?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/StarterConstants.java | 3 +- .../core/repository/entity/ExtAxProperty.java | 6 ++- .../impl/ExtAxPropertyServiceImpl.java | 6 +++ .../main/resources/sql/upgrade_to_1.4.0.sql | 3 ++ .../server/WorkflowEnginApplication.java | 3 ++ .../RequestHeaderContextInterceptor.java | 43 +++++++++++-------- .../NonContainerEnvironmentCondition.java | 8 ++-- .../feign/ext/ComplexInvokeClient.java | 3 +- .../ext/WorkflowEngineStarterDecoder.java | 2 +- ...rkflowEngineStarterFeignConfiguration.java | 4 +- ...WorkflowEngineStarterDefaultMQMonitor.java | 2 +- ...kflowEngineStarterMQMonitorController.java | 2 +- 12 files changed, 54 insertions(+), 31 deletions(-) rename {workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter => workflow-engine-common/src/main/java/cn/axzo/workflow}/common/constant/StarterConstants.java (80%) create mode 100644 workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.0.sql diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/StarterConstants.java similarity index 80% rename from workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java rename to workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/StarterConstants.java index 3adb0d1eb..66747128f 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/constant/StarterConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/StarterConstants.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.starter.common.constant; +package cn.axzo.workflow.common.constant; /** * Starter 常量类 @@ -12,4 +12,5 @@ public interface StarterConstants { String K8S_POD_NAME_SPACE = "MY_POD_NAMESPACE"; String NACOS_PROFILES_ACTIVE = "NACOS_PROFILES_ACTIVE"; String MQ_GID_NAME_SEGMENT = "GID_SEGMENT"; + String ENABLE_MANAGEABLE = "ENABLE_MANAGEABLE"; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProperty.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProperty.java index 79272e41d..9fd14518d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProperty.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProperty.java @@ -34,5 +34,9 @@ public class ExtAxProperty extends BaseEntity { @TableField("value") private String value; - + /** + * 接入方是否使用了 manageable + */ + @TableField("manageable") + private Boolean manageable; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java index f496a7208..b43914586 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java @@ -5,6 +5,9 @@ import cn.axzo.workflow.core.repository.mapper.ExtAxPropertyMapper; import cn.axzo.workflow.core.service.ExtAxPropertyService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -23,18 +26,21 @@ public class ExtAxPropertyServiceImpl implements ExtAxPropertyService { @Resource private ExtAxPropertyMapper mapper; + @CacheEvict(value = "property", key = "#property.name") @Override public ExtAxProperty add(ExtAxProperty property) { mapper.insert(property); return property; } + @CachePut(value = "property", key = "property.name") @Override public ExtAxProperty update(ExtAxProperty property) { mapper.updateById(property); return property; } + @Cacheable(value = "property", key = "#name") @Override public Optional getByName(String name) { if (!StringUtils.hasText(name)) { diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.0.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.0.sql new file mode 100644 index 000000000..4905c4e7d --- /dev/null +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.0.sql @@ -0,0 +1,3 @@ +alter table ext_ax_property + add manageable boolean default false null comment '接入方是否使用了 manageable'; + diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java index 131f005b9..697702527 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java @@ -1,9 +1,11 @@ package cn.axzo.workflow.server; +import liquibase.pro.packaged.E; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ComponentScan; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -12,6 +14,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @ComponentScan({"cn.axzo.workflow", "cn.axzo.maokai"}) @SpringBootApplication(exclude = RabbitAutoConfiguration.class) @EnableTransactionManagement +@EnableCaching public class WorkflowEnginApplication { public static void main(String[] args) { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java index 3ca7631bd..233b12fc7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java @@ -23,6 +23,7 @@ import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_H import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130; +import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE; import static cn.axzo.workflow.core.common.code.OtherRespCode.CLIENT_VERSION_SUPPORT; import static cn.axzo.workflow.core.common.code.OtherRespCode.MICRO_SERVER_NEED_REBUILD; @@ -79,49 +80,53 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { private void recordClientInfo(HttpServletRequest request, String headerClientVersion, DefaultArtifactVersion clientVersion) { - log.info("HEADER_SERVER_NAME : {}", request.getHeader(HEADER_SERVER_NAME)); - if (!StringUtils.hasText(request.getHeader(HEADER_SERVER_NAME))) { + String applicationName = request.getHeader(HEADER_SERVER_NAME); + log.info("HEADER_SERVER_NAME : {}", applicationName); + if (!StringUtils.hasText(applicationName)) { return; } + String manageableStatus = request.getHeader(ENABLE_MANAGEABLE); - String requestApplicationName = request.getHeader(HEADER_SERVER_NAME); - Optional extAxProperty = extAxPropertyService.getByName(requestApplicationName); - String cacheRepeatKey = REPEAT_KEY + requestApplicationName; + Optional extAxProperty = extAxPropertyService.getByName(applicationName); + String cacheRepeatKey = REPEAT_KEY + applicationName; log.info("repeatApi key: {}", cacheRepeatKey); String key = RedisUtils.getCacheObject(cacheRepeatKey); if (Objects.isNull(key)) { RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofSeconds(5)); KEY_CACHE.set(cacheRepeatKey); - insert(extAxProperty, headerClientVersion, clientVersion); - } else { - update(extAxProperty, headerClientVersion, clientVersion); + insert(extAxProperty, applicationName, clientVersion, manageableStatus); } } - private void update(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion) { + private void update(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) { if (!extAxProperty.isPresent()) { return; } ExtAxProperty property = extAxProperty.get(); - if (Objects.equals(property.getValue(), clientVersion.toString())) { + if (Objects.equals(property.getValue(), clientVersion.toString()) + && Objects.equals(property.getManageable().toString(), manageableStatus)) { return; } + property.setName(requestApplicationName); property.setValue(clientVersion.toString()); + property.setManageable(Boolean.valueOf(manageableStatus)); extAxPropertyService.update(property); } - private void insert(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion) { + private void insert(Optional extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) { if (extAxProperty.isPresent()) { - return; + update(extAxProperty, requestApplicationName, clientVersion, manageableStatus); + } else { + extAxPropertyService.add(extAxProperty.orElseGet(() -> { + ExtAxProperty property = new ExtAxProperty(); + property.setCreated(true); + property.setName(requestApplicationName); + property.setValue(clientVersion.toString()); + property.setManageable(Boolean.valueOf(manageableStatus)); + return property; + })); } - extAxPropertyService.add(extAxProperty.orElseGet(() -> { - ExtAxProperty property = new ExtAxProperty(); - property.setCreated(true); - property.setName(requestApplicationName); - property.setValue(clientVersion.toString()); - return property; - })); } private void printHeader(HttpServletRequest request) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java index c942f6870..153aafe0c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/common/condition/NonContainerEnvironmentCondition.java @@ -11,10 +11,10 @@ import org.springframework.util.StringUtils; import java.util.Objects; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.DEBUGGING_MQ_SUFFIX; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.K8S_POD_NAME_SPACE; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.NACOS_PROFILES_ACTIVE; +import static cn.axzo.workflow.common.constant.StarterConstants.DEBUGGING_MQ_SUFFIX; +import static cn.axzo.workflow.common.constant.StarterConstants.K8S_POD_NAME_SPACE; +import static cn.axzo.workflow.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.common.constant.StarterConstants.NACOS_PROFILES_ACTIVE; /** * 用于处理 MQ 的消费者, 在本地启动或在容器中启动时, 能自主控制是否并入统一的消费组 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 6c12cb58a..017237e0e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -3,7 +3,6 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; -import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; @@ -49,7 +48,7 @@ import java.util.regex.Pattern; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; +import static cn.axzo.workflow.common.constant.StarterConstants.STARTER_INVOKE_MODE; import static java.nio.charset.StandardCharsets.UTF_8; /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index 4575c2032..a6aa43f3c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -77,7 +77,7 @@ final class WorkflowEngineStarterDecoder implements Decoder { if (response.status() == 202) { log.warn("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg()); throw new WorkflowRpcInvokeException(commonResponse.getMsg()); - } else { + } else if (response.status() != 200) { log.error("WorkflowEngineStarterDecoder has error, status:{} msg: {}", response.status(), commonResponse.getMsg()); } return commonResponse.getData(); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index a3f1aef28..4721b7bc3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -32,7 +32,8 @@ import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_A import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.STARTER_INVOKE_MODE; +import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE; +import static cn.axzo.workflow.common.constant.StarterConstants.STARTER_INVOKE_MODE; import static java.util.concurrent.TimeUnit.SECONDS; /** @@ -78,6 +79,7 @@ public class WorkflowEngineStarterFeignConfiguration { } //链路追踪 template.header(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC)); + template.header(ENABLE_MANAGEABLE, starterProperties.getManageable().toString()); }; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index fb623dfd3..bd3677106 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -17,7 +17,7 @@ import org.springframework.util.CollectionUtils; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.BROADCAST_CONSUMER_GROUP; import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.RPC_RETRY_CONSUMER_GROUP; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index 1f3f1e523..dce45ebe7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -20,7 +20,7 @@ import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; -import static cn.axzo.workflow.starter.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; import static cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor.DLQ_PREFIX; /** From aa9cd63791dd7749e112665f511ab8bf1e025245 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 18 Jun 2024 18:32:07 +0800 Subject: [PATCH 170/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20cachePut=20=E4=BD=BF=E7=94=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/service/impl/ExtAxPropertyServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java index b43914586..7ebf4702d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxPropertyServiceImpl.java @@ -33,7 +33,7 @@ public class ExtAxPropertyServiceImpl implements ExtAxPropertyService { return property; } - @CachePut(value = "property", key = "property.name") + @CachePut(value = "property", key = "#property.name") @Override public ExtAxProperty update(ExtAxProperty property) { mapper.updateById(property); From b085fbd6f133460042f44152d0078705c94d24b1 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 11:11:49 +0800 Subject: [PATCH 171/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=86=85=E7=BD=AE=E9=92=89=E9=92=89=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterProperties.java | 13 +++++++++ .../mq/monitor/AlertBroadcastDLQReporter.java | 12 ++++++++ .../mq/monitor/AlertRcpDLQReporter.java | 12 ++++++++ ...WorkflowEngineStarterDefaultMQMonitor.java | 25 ++++++++++++---- ...kflowEngineStarterMQMonitorController.java | 29 ++++++++++++++++++- 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 2fcfe42a5..1b28ef3dc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -77,6 +77,11 @@ public class WorkflowEngineStarterProperties { */ private long dlqMonitorIntervalInMs = 4 * 60 * 60 * 1000L; + /** + * 开启后,会在主动给“工作流小分队”群中发送信息 + */ + private Boolean alert = false; + public Boolean getManageable() { return manageable; } @@ -140,4 +145,12 @@ public class WorkflowEngineStarterProperties { public void setDlqMonitorIntervalInMs(long dlqMonitorIntervalInMs) { this.dlqMonitorIntervalInMs = dlqMonitorIntervalInMs; } + + public Boolean getAlert() { + return alert; + } + + public void setAlert(Boolean alert) { + this.alert = alert; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java new file mode 100644 index 000000000..5ea792d16 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java @@ -0,0 +1,12 @@ +package cn.axzo.workflow.starter.mq.monitor; + +import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQReporter; + +/** + * TODO + * + * @author wangli + * @since 2024/6/19 11:04 + */ +public class AlertBroadcastDLQReporter implements BroadcastDLQReporter { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java new file mode 100644 index 000000000..4152fca62 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java @@ -0,0 +1,12 @@ +package cn.axzo.workflow.starter.mq.monitor; + +import cn.axzo.workflow.starter.handler.monitor.RpcDLQReporter; + +/** + * TODO + * + * @author wangli + * @since 2024/6/19 11:04 + */ +public class AlertRcpDLQReporter implements RpcDLQReporter { +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index bd3677106..b354d87b6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -39,8 +39,8 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private final DefaultMQAdminExt defaultMQAdminExt; private final Environment environment; private final ThreadPoolTaskScheduler taskScheduler; - private final BroadcastDLQReporter broadcastDLQProcessor; - private final RpcDLQReporter rpcDLQProcessor; + private BroadcastDLQReporter broadcastDLQProcessor; + private RpcDLQReporter rpcDLQProcessor; private final WorkflowEngineStarterProperties starterProperties; private final AtomicBoolean running = new AtomicBoolean(false); @@ -51,10 +51,15 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { Environment environment) { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; - this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQReporter() { - }); - this.rpcDLQProcessor = rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQReporter() { - }); + if (workflowEngineStarterProperties.getAlert()) { + this.broadcastDLQProcessor = new AlertBroadcastDLQReporter(); + this.rpcDLQProcessor = new AlertRcpDLQReporter(); + } else { + this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQReporter() { + }); + this.rpcDLQProcessor = rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQReporter() { + }); + } this.starterProperties = workflowEngineStarterProperties; this.taskScheduler = init(); } @@ -105,6 +110,14 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { } } + public void setBroadcastDLQProcessor(BroadcastDLQReporter broadcastDLQProcessor) { + this.broadcastDLQProcessor = broadcastDLQProcessor; + } + + public void setRpcDLQProcessor(RpcDLQReporter rpcDLQProcessor) { + this.rpcDLQProcessor = rpcDLQProcessor; + } + @Override public boolean isAutoStartup() { if (starterProperties.getEnableDlqMonitor() && starterProperties.getRpcMonitorStatus()) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index dce45ebe7..aaab6ea49 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -1,6 +1,10 @@ package cn.axzo.workflow.starter.mq.monitor.console; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQReporter; +import cn.axzo.workflow.starter.handler.monitor.RpcDLQReporter; +import cn.axzo.workflow.starter.mq.monitor.AlertBroadcastDLQReporter; +import cn.axzo.workflow.starter.mq.monitor.AlertRcpDLQReporter; import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; import cn.azxo.framework.common.model.CommonResponse; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; @@ -19,8 +23,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; import static cn.axzo.workflow.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; +import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; import static cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor.DLQ_PREFIX; /** @@ -40,6 +44,10 @@ public class WorkflowEngineStarterMQMonitorController { @Resource private ObjectProvider monitorObjectProvider; @Resource + private ObjectProvider broadcastDLQProcessorObjectProvider; + @Resource + private ObjectProvider rpcDLQProcessorObjectProvider; + @Resource private Environment environment; @Value("${spring.application.name}") private String applicationName; @@ -117,4 +125,23 @@ public class WorkflowEngineStarterMQMonitorController { "在应用重启前,将不再监控。重启后,将根据环境变量配置来确定是否监控。"); } } + + @GetMapping("/m/a/set") + public CommonResponse changeDLQAlert(@RequestParam("status") Boolean status) { + WorkflowEngineStarterDefaultMQMonitor monitor = monitorObjectProvider.getIfAvailable(); + if (Objects.isNull(monitor)) { + return CommonResponse.success("未开启·死信队列·的监控,如需,请设置 workflow.engine.starter.enableDlqMonitor = true 后再重试!"); + } + if (status) { + monitor.setBroadcastDLQProcessor(new AlertBroadcastDLQReporter()); + monitor.setRpcDLQProcessor(new AlertRcpDLQReporter()); + return CommonResponse.success("开启 DLQ 钉钉通知"); + } else { + monitor.setBroadcastDLQProcessor(broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQReporter() { + })); + monitor.setRpcDLQProcessor(rpcDLQProcessorObjectProvider.getIfAvailable(() -> new RpcDLQReporter() { + })); + return CommonResponse.success("以关闭 DLQ 钉钉通知"); + } + } } From 1f96e581d8b0767f3f4c61da047d537321cf4a09 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 11:23:06 +0800 Subject: [PATCH 172/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=86=85=E7=BD=AE=E9=92=89=E9=92=89=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 15 +++-- .../mq/monitor/AlertBroadcastDLQReporter.java | 64 ++++++++++++++++++- .../mq/monitor/AlertRcpDLQReporter.java | 64 ++++++++++++++++++- ...WorkflowEngineStarterDefaultMQMonitor.java | 4 +- ...kflowEngineStarterMQMonitorController.java | 4 +- 5 files changed, 140 insertions(+), 11 deletions(-) diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index 012ce6cf9..d850cc52f 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -20,20 +20,25 @@ spring-boot-configuration-processor true - - ${project.groupId} - workflow-engine-api - ${project.version} - cn.axzo.framework.rocketmq axzo-common-rocketmq provided + + com.aliyun + alibaba-dingtalk-service-sdk + provided + org.apache.rocketmq rocketmq-tools 4.9.1 + + ${project.groupId} + workflow-engine-api + ${project.version} + diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java index 5ea792d16..ebd169758 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java @@ -1,12 +1,74 @@ package cn.axzo.workflow.starter.mq.monitor; import cn.axzo.workflow.starter.handler.monitor.BroadcastDLQReporter; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.dingtalk.api.response.OapiRobotSendResponse; +import lombok.SneakyThrows; +import org.apache.rocketmq.common.admin.TopicOffset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; /** - * TODO + * Starter 内置的 Broadcast DLQ 钉钉通知 * * @author wangli * @since 2024/6/19 11:04 */ public class AlertBroadcastDLQReporter implements BroadcastDLQReporter { + + private static final Logger log = LoggerFactory.getLogger(AlertBroadcastDLQReporter.class); + private final String dingtalk_robot_webhook = "https://oapi.dingtalk.com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; + private final String profile; + private final String applicationName; + + public AlertBroadcastDLQReporter(Environment environment) { + this.profile = environment.getProperty("spring.profiles.active"); + this.applicationName = environment.getProperty("spring.application.name"); + } + + @Override + public void process(TopicOffset v) { + log.warn("found DLQ"); + long count = v.getMaxOffset() - v.getMinOffset(); + if (count > 0) { + sendDingTalk(count); + } + } + + @SneakyThrows + public void sendDingTalk(Long count) { + DingTalkClient client = new DefaultDingTalkClient(dingtalk_robot_webhook); + OapiRobotSendRequest request = new OapiRobotSendRequest(); + + request.setMsgtype("markdown"); + OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); + markdown.setTitle("Notice Env: " + profile); + markdown.setText("#### [" + profile + "]环境[" + applicationName + "]发现“DLQ”数据(Rpc)\n" + + "> ###### 1. 如需查看详情,[请点击这里](" + findDomain() + "m) \n" + + "> ###### 2. 如需调整 MQ DLQ 的监控状态: \n" + + "[关闭监控](" + findDomain() + "m/set?status=false) \n | " + + "[开启监控](" + findDomain() + "m/set?status=true) \n" + + "> 积累条数:" + count + " \n"); + request.setMarkdown(markdown); + log.warn(markdown.getText()); + OapiRobotSendResponse response = client.execute(request); + } + + private String findDomain() { + switch (profile) { + case "dev": + return "https://dev-app.axzo.cn/" + applicationName + "/web/we/s/"; + case "test": + return "https://test-api.axzo.cn/" + applicationName + "/web/we/s/"; + case "pre": + return "https://pre-api.axzo.cn/" + applicationName + "/web/we/s/"; + case "live": + return "https://live-api.axzo.cn/" + applicationName + "/web/we/s/"; + default: + return "https://api.axzo.cn/" + applicationName + "/web/we/s/"; + } + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java index 4152fca62..3ddf33306 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java @@ -1,12 +1,74 @@ package cn.axzo.workflow.starter.mq.monitor; import cn.axzo.workflow.starter.handler.monitor.RpcDLQReporter; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.dingtalk.api.response.OapiRobotSendResponse; +import lombok.SneakyThrows; +import org.apache.rocketmq.common.admin.TopicOffset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; /** - * TODO + * Starter 内置的 Rpc DLQ 钉钉通知 * * @author wangli * @since 2024/6/19 11:04 */ public class AlertRcpDLQReporter implements RpcDLQReporter { + + private static final Logger log = LoggerFactory.getLogger(AlertRcpDLQReporter.class); + private final String dingtalk_robot_webhook = "https://oapi.dingtalk.com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; + private final String profile; + private final String applicationName; + + public AlertRcpDLQReporter(Environment environment) { + this.profile = environment.getProperty("spring.profiles.active"); + this.applicationName = environment.getProperty("spring.application.name"); + } + + @Override + public void process(TopicOffset v) { + log.warn("found DLQ"); + long count = v.getMaxOffset() - v.getMinOffset(); + if (count > 0) { + sendDingTalk(count); + } + } + + @SneakyThrows + public void sendDingTalk(Long count) { + DingTalkClient client = new DefaultDingTalkClient(dingtalk_robot_webhook); + OapiRobotSendRequest request = new OapiRobotSendRequest(); + + request.setMsgtype("markdown"); + OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); + markdown.setTitle("Notice Env: " + profile); + markdown.setText("#### [" + profile + "]环境[" + applicationName + "]发现“DLQ”数据(Rpc)\n" + + "> ###### 1. 如需查看详情,[请点击这里](" + findDomain() + "m) \n" + + "> ###### 2. 如需调整 MQ DLQ 的监控状态: \n" + + "[关闭监控](" + findDomain() + "m/set?status=false) \n | " + + "[开启监控](" + findDomain() + "m/set?status=true) \n" + + "> 积累条数:" + count + " \n"); + request.setMarkdown(markdown); + log.warn(markdown.getText()); + OapiRobotSendResponse response = client.execute(request); + } + + private String findDomain() { + switch (profile) { + case "dev": + return "https://dev-app.axzo.cn/" + applicationName + "/web/we/s/"; + case "test": + return "https://test-api.axzo.cn/" + applicationName + "/web/we/s/"; + case "pre": + return "https://pre-api.axzo.cn/" + applicationName + "/web/we/s/"; + case "live": + return "https://live-api.axzo.cn/" + applicationName + "/web/we/s/"; + default: + return "https://api.axzo.cn/" + applicationName + "/web/we/s/"; + } + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index b354d87b6..813a1c9d3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -52,8 +52,8 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { this.defaultMQAdminExt = mqAdminExtObjectProvider.getIfAvailable(); this.environment = environment; if (workflowEngineStarterProperties.getAlert()) { - this.broadcastDLQProcessor = new AlertBroadcastDLQReporter(); - this.rpcDLQProcessor = new AlertRcpDLQReporter(); + this.broadcastDLQProcessor = new AlertBroadcastDLQReporter(environment); + this.rpcDLQProcessor = new AlertRcpDLQReporter(environment); } else { this.broadcastDLQProcessor = broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQReporter() { }); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java index aaab6ea49..2d4bf6dff 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/console/WorkflowEngineStarterMQMonitorController.java @@ -133,8 +133,8 @@ public class WorkflowEngineStarterMQMonitorController { return CommonResponse.success("未开启·死信队列·的监控,如需,请设置 workflow.engine.starter.enableDlqMonitor = true 后再重试!"); } if (status) { - monitor.setBroadcastDLQProcessor(new AlertBroadcastDLQReporter()); - monitor.setRpcDLQProcessor(new AlertRcpDLQReporter()); + monitor.setBroadcastDLQProcessor(new AlertBroadcastDLQReporter(environment)); + monitor.setRpcDLQProcessor(new AlertRcpDLQReporter(environment)); return CommonResponse.success("开启 DLQ 钉钉通知"); } else { monitor.setBroadcastDLQProcessor(broadcastDLQProcessorObjectProvider.getIfAvailable(() -> new BroadcastDLQReporter() { From 0aeafbc6c326ac58e53d590a150a026141b25c28 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 13:49:42 +0800 Subject: [PATCH 173/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=86=85=E7=BD=AE=E9=92=89=E9=92=89=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/WorkflowEngineStarterProperties.java | 2 ++ .../starter/handler/monitor/BroadcastDLQReporter.java | 2 +- .../starter/handler/monitor/RpcDLQReporter.java | 2 +- .../starter/mq/monitor/AlertBroadcastDLQReporter.java | 7 ++++--- .../starter/mq/monitor/AlertRcpDLQReporter.java | 7 ++++--- .../monitor/WorkflowEngineStarterDefaultMQMonitor.java | 10 ++++++++-- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 1b28ef3dc..584d75484 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -79,6 +79,8 @@ public class WorkflowEngineStarterProperties { /** * 开启后,会在主动给“工作流小分队”群中发送信息 + *

+ * 只针对容器环境中的应用生效 */ private Boolean alert = false; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java index e5689a4db..9305f449c 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/BroadcastDLQReporter.java @@ -17,7 +17,7 @@ import org.slf4j.LoggerFactory; public interface BroadcastDLQReporter { Logger log = LoggerFactory.getLogger(BroadcastDLQReporter.class); - default void process(TopicOffset v) { + default void process(TopicOffset v, String dlqName) { long dlqCount = v.getMaxOffset() - v.getMinOffset(); log.error("found Broadcast MQ DLQ, count: {}", dlqCount); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java index 9ce1e7a01..ceeffc63e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/handler/monitor/RpcDLQReporter.java @@ -18,7 +18,7 @@ import org.slf4j.LoggerFactory; public interface RpcDLQReporter { Logger log = LoggerFactory.getLogger(RpcDLQReporter.class); - default void process(TopicOffset v) { + default void process(TopicOffset v, String dlqName) { long dlqCount = v.getMaxOffset() - v.getMinOffset(); log.error("found rpc MQ DLQ, count: {}", dlqCount); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java index ebd169758..97a7a24ae 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertBroadcastDLQReporter.java @@ -30,16 +30,16 @@ public class AlertBroadcastDLQReporter implements BroadcastDLQReporter { } @Override - public void process(TopicOffset v) { + public void process(TopicOffset v, String dlqName) { log.warn("found DLQ"); long count = v.getMaxOffset() - v.getMinOffset(); if (count > 0) { - sendDingTalk(count); + sendDingTalk(count, dlqName); } } @SneakyThrows - public void sendDingTalk(Long count) { + public void sendDingTalk(Long count, String dlqName) { DingTalkClient client = new DefaultDingTalkClient(dingtalk_robot_webhook); OapiRobotSendRequest request = new OapiRobotSendRequest(); @@ -49,6 +49,7 @@ public class AlertBroadcastDLQReporter implements BroadcastDLQReporter { markdown.setText("#### [" + profile + "]环境[" + applicationName + "]发现“DLQ”数据(Rpc)\n" + "> ###### 1. 如需查看详情,[请点击这里](" + findDomain() + "m) \n" + "> ###### 2. 如需调整 MQ DLQ 的监控状态: \n" + + "> ###### 3. DLQ名称:" + dlqName + " \n" + "[关闭监控](" + findDomain() + "m/set?status=false) \n | " + "[开启监控](" + findDomain() + "m/set?status=true) \n" + "> 积累条数:" + count + " \n"); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java index 3ddf33306..3619f7f83 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/AlertRcpDLQReporter.java @@ -30,16 +30,16 @@ public class AlertRcpDLQReporter implements RpcDLQReporter { } @Override - public void process(TopicOffset v) { + public void process(TopicOffset v, String dlqName) { log.warn("found DLQ"); long count = v.getMaxOffset() - v.getMinOffset(); if (count > 0) { - sendDingTalk(count); + sendDingTalk(count, dlqName); } } @SneakyThrows - public void sendDingTalk(Long count) { + public void sendDingTalk(Long count, String dlqName) { DingTalkClient client = new DefaultDingTalkClient(dingtalk_robot_webhook); OapiRobotSendRequest request = new OapiRobotSendRequest(); @@ -49,6 +49,7 @@ public class AlertRcpDLQReporter implements RpcDLQReporter { markdown.setText("#### [" + profile + "]环境[" + applicationName + "]发现“DLQ”数据(Rpc)\n" + "> ###### 1. 如需查看详情,[请点击这里](" + findDomain() + "m) \n" + "> ###### 2. 如需调整 MQ DLQ 的监控状态: \n" + + "> ###### 3. DLQ名称:" + dlqName + " \n" + "[关闭监控](" + findDomain() + "m/set?status=false) \n | " + "[开启监控](" + findDomain() + "m/set?status=true) \n" + "> 积累条数:" + count + " \n"); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 813a1c9d3..578f05d3a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -13,10 +13,12 @@ import org.springframework.context.SmartLifecycle; import org.springframework.core.env.Environment; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; +import static cn.axzo.workflow.common.constant.StarterConstants.K8S_POD_NAME_SPACE; import static cn.axzo.workflow.common.constant.StarterConstants.MQ_GID_NAME_SEGMENT; import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.BROADCAST_CONSUMER_GROUP; import static cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController.RPC_RETRY_CONSUMER_GROUP; @@ -91,6 +93,10 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { private void compareDLQ(String consumerGroupName, String dqlType) { log.info("current broadcast consumer group is :{}", consumerGroupName); + String myPodNamespace = environment.getProperty(K8S_POD_NAME_SPACE); + if (!StringUtils.hasText(myPodNamespace)) { + return; + } try { TopicStatsTable table = defaultMQAdminExt.examineTopicStats(DLQ_PREFIX + consumerGroupName); if (Objects.isNull(table) || CollectionUtils.isEmpty(table.getOffsetTable())) { @@ -99,9 +105,9 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { table.getOffsetTable().forEach((k, v) -> { if (Objects.equals(DLQ_PREFIX + consumerGroupName, k.getTopic())) { if (BROADCAST.equals(dqlType)) { - broadcastDLQProcessor.process(v); + broadcastDLQProcessor.process(v, DLQ_PREFIX + consumerGroupName); } else if (RPC.equals(dqlType)) { - rpcDLQProcessor.process(v); + rpcDLQProcessor.process(v, DLQ_PREFIX + consumerGroupName); } } }); From a8d947f0f148676092cc14c879d2ebeda25a861b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 16:55:18 +0800 Subject: [PATCH 174/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=A4=84=E7=90=86=E4=BA=8B=E4=BB=B6=E4=B8=AD=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E6=AD=A3=E7=A1=AE=E8=BF=94=E5=9B=9E=20processDefiniti?= =?UTF-8?q?onKey=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/listener/AbstractBpmnEventListener.java | 2 +- .../listener/activity/RocketMqBpmActivityEventListener.java | 5 ++++- .../listener/notice/RocketMqMessagePushEventListener.java | 4 +++- .../listener/process/RocketMqBpmnProcessEventListener.java | 5 ++++- .../listener/task/RocketMqBpmnTaskEvent_102_Listener.java | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java index 5fa245c7d..8a9c3aae3 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/AbstractBpmnEventListener.java @@ -36,7 +36,7 @@ public abstract class AbstractBpmnEventListener impl } public static String parseProcessDefinitionKey(String processDefinitionId) { - if (StringUtils.hasText(processDefinitionId)) { + if (!StringUtils.hasText(processDefinitionId)) { return ""; } return processDefinitionId.split(":")[0]; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java index 27abc8004..5ddcdc1d9 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.Collections; @@ -183,7 +184,9 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener< return; } Map header = new HashMap<>(); - header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + } eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java index 5b216ebfe..c43fac1d0 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java @@ -392,7 +392,9 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener< return; } Map header = new HashMap<>(); - header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + } eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java index 0b823bc06..6aaa23bb5 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.HashMap; @@ -275,7 +276,9 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener< return; } Map header = new HashMap<>(); - header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + } eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index 8a85e4fc5..009e40339 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -137,7 +137,9 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene return; } Map header = new HashMap<>(); - header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); + } eventProducer.send(Event.builder() .shardingKey(dto.getProcessInstanceId()) .eventCode(eventEnum.getEventCode()) From 08e469ce711c487a9cc42b7fbd7742fcc65fbd63 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 17:37:42 +0800 Subject: [PATCH 175/210] =?UTF-8?q?update(REQ-2516)=20-=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E4=B8=80=E4=BA=9B=E5=BC=82=E5=B8=B8=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E7=9A=84=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...timisticLockingExceptionHandlerAdvice.java | 30 +++++++++++++++++++ .../common/annotation/ReporterType.java | 13 ++++---- .../common/aspectj/ErrorReportAspect.java | 7 ++++- 3 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java new file mode 100644 index 000000000..dcab1a555 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java @@ -0,0 +1,30 @@ +package cn.axzo.workflow.server.advice; + +import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties; +import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler; +import cn.axzo.framework.domain.web.code.IRespCode; +import cn.axzo.framework.domain.web.code.RespCode; +import org.flowable.common.engine.api.FlowableOptimisticLockingException; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.springframework.stereotype.Component; + +import static cn.axzo.framework.domain.web.code.BaseCode.UNAVAILABLE_FOR_LEGAL_REASONS; + +/** + * 降级 FlowableOptimisticLockingException 异常,该异常在 Flowable 框架中是可以忽略的 + * + * @author wangli + * @see CommandContext#logException() + * @since 2024/6/19 17:32 + */ +@Component +public class FlowableOptimisticLockingExceptionHandlerAdvice extends AbstractExceptionApiResultHandler { + public FlowableOptimisticLockingExceptionHandlerAdvice(RespErrorCodeMappingProperties properties) { + super(properties); + } + + @Override + protected IRespCode decode(FlowableOptimisticLockingException ex, IRespCode fallbackCode) { + return new RespCode(UNAVAILABLE_FOR_LEGAL_REASONS.getCode(), ex.getMessage()); + } +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java index 0ad2a3894..e42b9df9d 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java @@ -1,8 +1,6 @@ package cn.axzo.workflow.server.common.annotation; -import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.server.common.util.DingTalkUtils; -import cn.azxo.framework.common.utils.LogUtil; import lombok.extern.slf4j.Slf4j; import static cn.axzo.workflow.server.common.aspectj.RepeatSubmitAspect.argsArrayToString; @@ -71,10 +69,11 @@ public enum ReporterType { public abstract void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, Throwable e, Boolean downgrade); private static void logWarn(Throwable throwable, String shortString) { - if (throwable instanceof WorkflowEngineException) { - log.warn("引擎内部正常业务异常类型,日志降级: " + throwable.getMessage(), throwable); - } else { - LogUtil.error(LogUtil.ErrorType.ERROR_BUSINESS, shortString, throwable.getMessage(), throwable); - } + // 由于框架底层 AbstractExceptionApiResultHandler 默认会打印,所以此处都只是降级打印 +// if (throwable instanceof WorkflowEngineException) { + log.warn("引擎内部正常业务异常类型,日志降级: " + throwable.getMessage(), throwable); +// } else { +// LogUtil.error(LogUtil.ErrorType.ERROR_BUSINESS, shortString, throwable.getMessage(), throwable); +// } } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java index d5b59e9e4..4c08332fb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.core.common.event.ApiLogEvent; import cn.axzo.workflow.server.common.annotation.EnvConfig; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.config.property.WorkflowProperties; +import com.google.common.collect.Lists; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; @@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.Arrays; +import java.util.List; import java.util.Objects; import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; @@ -47,6 +49,7 @@ public class ErrorReportAspect implements Ordered { private ApplicationEventPublisher applicationEventPublisher; @Resource private WorkflowProperties workflowProperties; + private static List methodNames = Lists.newArrayList("HealthCheckController.checkDeath()"); @Override public int getOrder() { @@ -65,7 +68,9 @@ public class ErrorReportAspect implements Ordered { watch.start(signature.toShortString()); Object result = joinPoint.proceed(); watch.stop(); - log.info("StopWatch '{}': running time = {} 's", watch.getLastTaskName(), watch.getTotalTimeSeconds()); + if (!methodNames.contains(watch.getLastTaskName())) { + log.info("StopWatch '{}': running time = {} 's", watch.getLastTaskName(), watch.getTotalTimeSeconds()); + } if (!signature.toShortString().contains("ExtAxApiLogServiceImpl")) { String type = getType(joinPoint); From ee9b41b158785b552ca12673f00ece3dd4290e5d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 17:54:30 +0800 Subject: [PATCH 176/210] =?UTF-8?q?update(REQ-2516)=20-=20=E6=89=93?= =?UTF-8?q?=E5=8D=B0=20MQ=20=E4=BA=8B=E4=BB=B6=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/activity/RocketMqBpmActivityEventListener.java | 1 + .../listener/notice/RocketMqMessagePushEventListener.java | 1 + .../listener/process/RocketMqBpmnProcessEventListener.java | 1 + .../listener/task/RocketMqBpmnTaskEvent_102_Listener.java | 1 + 4 files changed, 4 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java index 5ddcdc1d9..f6a54b77a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java @@ -185,6 +185,7 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener< } Map header = new HashMap<>(); if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + log.warn("record process definition key: {}", dto.getProcessDefinitionKey()); header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); } eventProducer.send(Event.builder() diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java index c43fac1d0..4fb2656f3 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java @@ -393,6 +393,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener< } Map header = new HashMap<>(); if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + log.warn("record process definition key: {}", dto.getProcessDefinitionKey()); header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); } eventProducer.send(Event.builder() diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java index 6aaa23bb5..bcfc2881a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/process/RocketMqBpmnProcessEventListener.java @@ -277,6 +277,7 @@ public class RocketMqBpmnProcessEventListener extends AbstractBpmnEventListener< } Map header = new HashMap<>(); if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + log.warn("record process definition key: {}", dto.getProcessDefinitionKey()); header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); } eventProducer.send(Event.builder() diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index 009e40339..f71f0278e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -138,6 +138,7 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene } Map header = new HashMap<>(); if (StringUtils.hasText(dto.getProcessDefinitionKey())) { + log.warn("record process definition key: {}", dto.getProcessDefinitionKey()); header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); } eventProducer.send(Event.builder() From 66748ea386a3c263b70b16681227492a4eb233f9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 18:17:46 +0800 Subject: [PATCH 177/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=86=85?= =?UTF-8?q?=E7=BD=AE=20ERROR=20=E7=BA=A7=E5=88=AB=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E5=88=B0=E6=8C=87=E5=AE=9A=E6=96=87=E4=BB=B6=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/logback-spring.xml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/workflow-engine-server/src/main/resources/logback-spring.xml b/workflow-engine-server/src/main/resources/logback-spring.xml index e56446467..a98188fa9 100644 --- a/workflow-engine-server/src/main/resources/logback-spring.xml +++ b/workflow-engine-server/src/main/resources/logback-spring.xml @@ -3,10 +3,35 @@ + + + ${LOG_PATH}/ERROR/error.log + + + ${LOG_PATH}/ERROR/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz + + 50MB + + 30 + + + + %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n + + + ERROR + + + + + + + + From b0cd1f8646fc8dcc86e1cea60d7d55e446fee4b8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 20:21:59 +0800 Subject: [PATCH 178/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=B8=9A=E5=8A=A1=E6=8C=87=E5=AE=9A=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=A0=A1=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/common/code/BpmnTaskRespCode.java | 1 + .../CustomBizSpecifyAssigneeToTaskCmd.java | 24 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java index cd2775b32..e3b3b5616 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java @@ -33,6 +33,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode { FIND_TASK_BY_PERSON_ID_ERROR("018", "流程实例中:【{}】未查找指定自然人:【{}】的待处理的流程任务!"), PROCESS_INSTANCE_IS_NOT_EXIST("019", "Execution:{} 对应流程实例不存在,流程状态异常!"), TASK_TYPE_MISMATCH("020", "节点类型不匹配,当前节点类型:【{}】,指定节点类型:【{}】!"), + PROCESS_CANT_SET_ASSIGNEE("021", "当前审批状态不允许设置审批人"), ; private String code; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java index 76cba22d2..543c0eb20 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java @@ -5,8 +5,10 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.api.Task; @@ -22,8 +24,10 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_R import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; +import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_ERROR; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_SET_ASSIGNEE; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.PROCESS_CANT_SET_ASSIGNEE; /** * 自定的业务指定审批人命令实现 @@ -53,6 +57,8 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command, Seri validTask(task); + validProcessInstance(commandContext, task); + changeAssigneeSnapshot(commandContext, task); addAssignee(commandContext, taskService, task); @@ -60,6 +66,20 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command, Seri return true; } + private void validProcessInstance(CommandContext commandContext, Task task) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + HistoryService historyService = processEngineConfiguration.getHistoryService(); + HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); + if (Objects.isNull(processInstance)) { + throw new WorkflowEngineException(PROCESS_INSTANCE_ID_NOT_EXISTS, task.getProcessInstanceId()); + } + if (!Objects.equals("PROCESSING", processInstance.getBusinessStatus())) { + throw new WorkflowEngineException(PROCESS_CANT_SET_ASSIGNEE); + } + } + + private void changeAssigneeSnapshot(CommandContext commandContext, Task task) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); @@ -85,9 +105,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command, Seri return; } - addedAssigners.forEach(i -> { - CustomTaskHelper.addMultiTask(commandContext, (TaskEntity) task, i); - }); + addedAssigners.forEach(i -> CustomTaskHelper.addMultiTask(commandContext, (TaskEntity) task, i)); taskService.setAssignee(task.getId(), HIDDEN_ASSIGNEE_ID); ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), DELETED.getStatus()); From 73f1361458de54a2b84063a7dec9bcc156122107 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 19 Jun 2024 20:22:36 +0800 Subject: [PATCH 179/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E4=B8=9A=E5=8A=A1=E6=8C=87=E5=AE=9A=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=A0=A1=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java index 543c0eb20..1ba3f8465 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java @@ -24,6 +24,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_R import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_ERROR; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_SET_ASSIGNEE; @@ -74,7 +75,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command, Seri if (Objects.isNull(processInstance)) { throw new WorkflowEngineException(PROCESS_INSTANCE_ID_NOT_EXISTS, task.getProcessInstanceId()); } - if (!Objects.equals("PROCESSING", processInstance.getBusinessStatus())) { + if (!Objects.equals(PROCESSING.getStatus(), processInstance.getBusinessStatus())) { throw new WorkflowEngineException(PROCESS_CANT_SET_ASSIGNEE); } } From 355d9c3d1a50563d842474553b0d15eadb72b60c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 20 Jun 2024 09:51:17 +0800 Subject: [PATCH 180/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E8=AE=BE=E7=BD=AE=E5=BC=82=E5=B8=B8=E7=9A=84=E5=A4=84?= =?UTF-8?q?=E7=90=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FlowableExceptionResultHandlerAdvice.java | 5 +-- ...timisticLockingExceptionHandlerAdvice.java | 3 +- ...traintViolationExceptionHandlerAdvice.java | 36 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/SQLIntegrityConstraintViolationExceptionHandlerAdvice.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableExceptionResultHandlerAdvice.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableExceptionResultHandlerAdvice.java index 00b8820cb..374e90fa0 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableExceptionResultHandlerAdvice.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableExceptionResultHandlerAdvice.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.server.advice; import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties; import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler; +import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.framework.domain.web.code.IRespCode; import cn.axzo.framework.domain.web.code.RespCode; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; @@ -30,8 +31,8 @@ public class FlowableExceptionResultHandlerAdvice extends AbstractExceptionApiRe protected IRespCode decode(FlowableException ex, IRespCode fallbackCode) { log.warn("发现 FlowableException Error: ", ex); if (Objects.nonNull(ex.getCause()) && ex.getCause() instanceof WorkflowEngineException) { - return new RespCode(UNAVAILABLE_FOR_LEGAL_REASONS.getCode(), ex.getCause().getMessage()); + return new RespCode(BaseCode.SUCCESS.getCode(), ex.getCause().getMessage()); } - return new RespCode(UNAVAILABLE_FOR_LEGAL_REASONS.getCode(), ex.getMessage()); + return new RespCode(BaseCode.SUCCESS.getCode(), ex.getMessage()); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java index dcab1a555..841a2d04e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/FlowableOptimisticLockingExceptionHandlerAdvice.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.server.advice; import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties; import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler; +import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.framework.domain.web.code.IRespCode; import cn.axzo.framework.domain.web.code.RespCode; import org.flowable.common.engine.api.FlowableOptimisticLockingException; @@ -25,6 +26,6 @@ public class FlowableOptimisticLockingExceptionHandlerAdvice extends AbstractExc @Override protected IRespCode decode(FlowableOptimisticLockingException ex, IRespCode fallbackCode) { - return new RespCode(UNAVAILABLE_FOR_LEGAL_REASONS.getCode(), ex.getMessage()); + return new RespCode(BaseCode.SUCCESS.getCode(), ex.getMessage()); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/SQLIntegrityConstraintViolationExceptionHandlerAdvice.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/SQLIntegrityConstraintViolationExceptionHandlerAdvice.java new file mode 100644 index 000000000..0a618d5fd --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/advice/SQLIntegrityConstraintViolationExceptionHandlerAdvice.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.server.advice; + +import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties; +import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler; +import cn.axzo.framework.domain.web.code.BaseCode; +import cn.axzo.framework.domain.web.code.IRespCode; +import cn.axzo.framework.domain.web.code.RespCode; +import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi; +import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import org.springframework.stereotype.Component; + +import java.sql.SQLIntegrityConstraintViolationException; + + +/** + * 处理多个接口同时操作一个流程实例时,可能会抛出数据库的异常,这种异常是可以被忽略的 + *

+ * 例如: {@link ProcessActivityApi#setAssignee(BpmnActivitySetAssigneeDTO)} 于 {@link ProcessInstanceApi#abortProcessInstance(BpmnProcessInstanceAbortDTO)} + * 两个接口并发访问时,由于 abort 先执行完,并提交事务后,setAssignee 方法内虽然有判断实例状态,但最后事务提交时突然发现实例状态被中止了就会抛出异常。 + * + * @author wangli + * @since 2024/6/20 09:42 + */ +@Component +public class SQLIntegrityConstraintViolationExceptionHandlerAdvice extends AbstractExceptionApiResultHandler { + public SQLIntegrityConstraintViolationExceptionHandlerAdvice(RespErrorCodeMappingProperties properties) { + super(properties); + } + + @Override + protected IRespCode decode(SQLIntegrityConstraintViolationException ex, IRespCode fallbackCode) { + return new RespCode(BaseCode.SUCCESS.getCode(), ex.getMessage()); + } +} From e1b2db65ad5001e76fd050fd44babf7b40fa8b6e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 20 Jun 2024 09:54:12 +0800 Subject: [PATCH 181/210] =?UTF-8?q?update(REQ-2516)=20-=20warn=20=E7=BA=A7?= =?UTF-8?q?=E5=88=AB=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=E5=88=B0=20warn?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6=E5=A4=B9=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/logback-spring.xml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/workflow-engine-server/src/main/resources/logback-spring.xml b/workflow-engine-server/src/main/resources/logback-spring.xml index a98188fa9..eaaa97bd8 100644 --- a/workflow-engine-server/src/main/resources/logback-spring.xml +++ b/workflow-engine-server/src/main/resources/logback-spring.xml @@ -23,6 +23,25 @@ + + + ${LOG_PATH}/WARN/warn.log + + + ${LOG_PATH}/WARN/%d{yyyy-MM}/warn.%d{yyyy-MM-dd}.%i.log.gz + + 50MB + + 30 + + + + %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n + + + WARN + + @@ -34,4 +53,9 @@ + + + + + From 7c4fce9c8948b3774d622737560153969fd9e58c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 20 Jun 2024 16:02:06 +0800 Subject: [PATCH 182/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E5=8E=86=E5=8F=B2=E7=89=88=E6=9C=AC=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/bpmn/BpmnProcessActivityController.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index d8c34a739..6d83c6c38 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -62,8 +62,14 @@ public class BpmnProcessActivityController implements ProcessActivityApi { return CommonResponse.success(true); } + /** + * old/trigger 地址是 1.3.3 版本以前的接口,在接入方未完全升级前,都需要保留 + * + * @param triggerId + * @return + */ @Operation(summary = "业务节点唤醒") - @GetMapping("/trigger") + @GetMapping({"/trigger", "/old/trigger"}) @Override @RepeatSubmit public CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId) { From 9edbf2f043aa7cf384c8dcbc33104a6dbef95dcd Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 24 Jun 2024 10:28:04 +0800 Subject: [PATCH 183/210] =?UTF-8?q?update(REQ-2516)=20-=20=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E5=A4=9A=E5=8A=A8=E4=BD=9C=E6=93=8D=E4=BD=9C=E5=90=8C?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B=E6=97=B6=EF=BC=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E7=BC=93=E8=AF=BB=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=88=A4=E6=96=AD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java index f43a8bb8b..be24a8a85 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java @@ -108,6 +108,9 @@ public class CustomCarbonCopyUserSelectorCmd implements Command Date: Mon, 24 Jun 2024 20:45:52 +0800 Subject: [PATCH 184/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=80=82?= =?UTF-8?q?=E9=85=8D=E6=A1=86=E6=9E=B6=E4=B8=AD=E6=8A=9B=E9=94=99=E7=9A=84?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-spring-boot-starter/pom.xml | 5 ++++ ...rkflowEngineStarterFeignConfiguration.java | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/workflow-engine-spring-boot-starter/pom.xml b/workflow-engine-spring-boot-starter/pom.xml index d850cc52f..3af6e195f 100644 --- a/workflow-engine-spring-boot-starter/pom.xml +++ b/workflow-engine-spring-boot-starter/pom.xml @@ -40,5 +40,10 @@ workflow-engine-api ${project.version} + + jakarta.servlet + jakarta.servlet-api + provided + diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 4721b7bc3..3199035da 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -22,12 +22,19 @@ import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; +import org.springframework.core.task.support.ExecutorServiceAdapter; import org.springframework.util.CollectionUtils; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Collections; import java.util.Objects; +import static cn.axzo.framework.web.exception.BasicRecordExceptionHandler.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; +import static cn.axzo.framework.web.exception.BasicRecordExceptionHandler.MICRO_SERVER_RECORD_ERROR_HEADER_NAME; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; @@ -80,9 +87,28 @@ public class WorkflowEngineStarterFeignConfiguration { //链路追踪 template.header(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC)); template.header(ENABLE_MANAGEABLE, starterProperties.getManageable().toString()); + HttpServletRequest originalRequest = getOriginalRequest(); + if (Objects.nonNull(originalRequest)) { + setRequestParams(template, originalRequest); + } }; } + private void setRequestParams(RequestTemplate template, HttpServletRequest originalRequest) { + String[] packageNames = originalRequest.getParameterValues(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME); + template.query(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME, packageNames); + } + + public HttpServletRequest getOriginalRequest() { + try { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + return attributes.getRequest(); + } catch (Exception e) { + log.warn("not HttpServletRequest instance bean found"); + return null; + } + } + private void resetInvokeMode(WorkflowEngineStarterProperties starterProperties, RequestTemplate template) { Collection invokeModeInHeader = template.headers().getOrDefault(STARTER_INVOKE_MODE, Collections.emptyList()); template.removeHeader(STARTER_INVOKE_MODE); From 6dd8fb4709ad1ba87fca2cb64b98b4cc879bed73 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 25 Jun 2024 18:55:58 +0800 Subject: [PATCH 185/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E6=8F=90=E4=BA=A4,=E8=AE=B0=E5=BD=95=E5=BE=AE?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E9=97=B4=E7=9A=84=E5=BC=82=E5=B8=B8=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RocketMqMessagePushEventListener.java | 1 + .../WorkflowEngineStarterErrorDecoder.java | 32 +++++++++++++++++++ ...rkflowEngineStarterFeignConfiguration.java | 11 ++++--- 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java index 4fb2656f3..820d255a7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java @@ -245,6 +245,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener< || !StringUtils.hasText(event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId())) { return; } + // TODO 这里的抄送人,不建议使用一个 MQ 事件来承载,而是一个人一个事件 log.info("RocketMqMessagePushEventListener#onCarbonCopy... cc' templateId: {}, receivePerson: {}, processInstanceId: {}", event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId()); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java new file mode 100644 index 000000000..5b6637b4a --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java @@ -0,0 +1,32 @@ +package cn.axzo.workflow.starter.feign.ext; + +import feign.Response; +import feign.Util; +import feign.codec.ErrorDecoder; + +import java.io.IOException; + +/** + * 为兼容 X-Metadata-Tag 的异常解码器 + * + * @author wangli + * @since 2024/6/25 18:02 + */ +public class WorkflowEngineStarterErrorDecoder implements ErrorDecoder { + private final ErrorDecoder errorDecoder = new Default(); + + @Override + public Exception decode(String methodKey, Response response) { + if (response.status() != 512) { + return errorDecoder.decode(methodKey, response); + } + byte[] body = {}; + try { + if (response.body() != null) { + body = Util.toByteArray(response.body().asInputStream()); + } + } catch (IOException ignored) { // NOPMD + } + return new Exception(); + } +} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 3199035da..03b7fdfa5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -11,6 +11,7 @@ import feign.RequestTemplate; import feign.Retryer; import feign.Target; import feign.codec.Decoder; +import feign.codec.ErrorDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -22,9 +23,7 @@ import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; -import org.springframework.core.task.support.ExecutorServiceAdapter; import org.springframework.util.CollectionUtils; -import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -33,8 +32,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Objects; -import static cn.axzo.framework.web.exception.BasicRecordExceptionHandler.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; -import static cn.axzo.framework.web.exception.BasicRecordExceptionHandler.MICRO_SERVER_RECORD_ERROR_HEADER_NAME; +import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; @@ -69,6 +67,11 @@ public class WorkflowEngineStarterFeignConfiguration { return new WorkflowEngineStarterDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters))); } + @Bean + public ErrorDecoder workflowEngineStarterErrorDecoder() { + return new WorkflowEngineStarterErrorDecoder(); + } + @Bean public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment, From 6ee4430f43e3cc199de80e533f52b43742469e0a Mon Sep 17 00:00:00 2001 From: wangli Date: Tue, 25 Jun 2024 22:04:12 +0800 Subject: [PATCH 186/210] =?UTF-8?q?update(REQ-2516)=20-=20=E9=85=8D?= =?UTF-8?q?=E5=90=88=E6=B5=8B=E8=AF=95=20X-Metadata-Tag=20=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E5=BC=82=E5=B8=B8=E4=BF=A1=E6=81=AF=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkflowEngineStarterErrorDecoder.java | 32 ------------------- ...rkflowEngineStarterFeignConfiguration.java | 6 ---- 2 files changed, 38 deletions(-) delete mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java deleted file mode 100644 index 5b6637b4a..000000000 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterErrorDecoder.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.axzo.workflow.starter.feign.ext; - -import feign.Response; -import feign.Util; -import feign.codec.ErrorDecoder; - -import java.io.IOException; - -/** - * 为兼容 X-Metadata-Tag 的异常解码器 - * - * @author wangli - * @since 2024/6/25 18:02 - */ -public class WorkflowEngineStarterErrorDecoder implements ErrorDecoder { - private final ErrorDecoder errorDecoder = new Default(); - - @Override - public Exception decode(String methodKey, Response response) { - if (response.status() != 512) { - return errorDecoder.decode(methodKey, response); - } - byte[] body = {}; - try { - if (response.body() != null) { - body = Util.toByteArray(response.body().asInputStream()); - } - } catch (IOException ignored) { // NOPMD - } - return new Exception(); - } -} diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 03b7fdfa5..1b58de635 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -11,7 +11,6 @@ import feign.RequestTemplate; import feign.Retryer; import feign.Target; import feign.codec.Decoder; -import feign.codec.ErrorDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -67,11 +66,6 @@ public class WorkflowEngineStarterFeignConfiguration { return new WorkflowEngineStarterDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters))); } - @Bean - public ErrorDecoder workflowEngineStarterErrorDecoder() { - return new WorkflowEngineStarterErrorDecoder(); - } - @Bean public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment, From 31f35737a2a80315dc3754cb16b142faa695a250 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 26 Jun 2024 10:00:15 +0800 Subject: [PATCH 187/210] =?UTF-8?q?update(REQ-2516)=20-=20=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E5=85=BC=E5=AE=B9,=E5=BE=85=20axzo-common=20=E5=8C=85?= =?UTF-8?q?=E5=90=88=E5=B9=B6master=20=E5=90=8E,=E4=BE=BF=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E4=BD=BF=E7=94=A8=E5=9F=BA=E7=A1=80=E7=B1=BB=E5=BA=93?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=B8=B8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/WorkflowEngineStarterFeignConfiguration.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 1b58de635..19a406cb3 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -31,7 +31,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Objects; -import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; +//import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; @@ -92,6 +92,7 @@ public class WorkflowEngineStarterFeignConfiguration { } private void setRequestParams(RequestTemplate template, HttpServletRequest originalRequest) { + String MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME = "pkg"; String[] packageNames = originalRequest.getParameterValues(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME); template.query(MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME, packageNames); } @@ -101,7 +102,7 @@ public class WorkflowEngineStarterFeignConfiguration { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); return attributes.getRequest(); } catch (Exception e) { - log.warn("not HttpServletRequest instance bean found"); + log.debug("not HttpServletRequest instance bean found"); return null; } } From b97152eb858ff5f1f01763d9789342d8f916db29 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 28 Jun 2024 10:49:41 +0800 Subject: [PATCH 188/210] =?UTF-8?q?update=20-=20=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/task/RocketMqBpmnTaskEvent_102_Listener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index f71f0278e..d56610415 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -138,7 +138,9 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene } Map header = new HashMap<>(); if (StringUtils.hasText(dto.getProcessDefinitionKey())) { - log.warn("record process definition key: {}", dto.getProcessDefinitionKey()); + if (log.isDebugEnabled()) { + log.debug("record process definition key: {}", dto.getProcessDefinitionKey()); + } header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); } eventProducer.send(Event.builder() From e23dd75c3c25702691b6a4ddeac664ac1bb5f2ef Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 15:16:33 +0800 Subject: [PATCH 189/210] =?UTF-8?q?hotfix/improve-batch-operation=20-=20?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=90=8C=E6=97=B6=E6=93=8D=E4=BD=9C=E5=90=8C?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/conf/FlowableConfiguration.java | 9 +- .../core/engine/cmd/AbstractCommand.java | 12 ++ .../cmd/CustomAbortProcessInstanceCmd.java | 10 +- .../core/engine/cmd/CustomApproveTaskCmd.java | 16 +- .../cmd/CustomCancelProcessInstanceCmd.java | 12 +- .../engine/cmd/CustomRejectionTaskCmd.java | 18 ++- .../CustomLockProcessInstanceInterceptor.java | 148 ++++++++++++++++++ 7 files changed, 220 insertions(+), 5 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 15302a561..1860b1b7b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.conf; import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory; import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory; import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator; +import cn.axzo.workflow.core.engine.interceptor.CustomLockProcessInstanceInterceptor; import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler; import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler; @@ -30,6 +31,8 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import java.time.Duration; import java.util.List; @@ -56,7 +59,8 @@ public class FlowableConfiguration { BpmnProcessActivityService bpmnProcessActivityService, List jobProcessors, NacosServiceManager nacosServiceManager, - NacosDiscoveryProperties nacosDiscoveryProperties) { + NacosDiscoveryProperties nacosDiscoveryProperties, + StringRedisTemplate redisTemplate) { return configuration -> { configuration.setEnableHistoricTaskLogging(true); configuration.setHistoryLevel(HistoryLevel.AUDIT); @@ -92,6 +96,9 @@ public class FlowableConfiguration { new CustomWorkflowEngineExceptionHandler(), new CustomAsyncRunnableExceptionExceptionHandler())); configuration.setCommandContextFactory(new CustomCommandContextFactory()); + configuration.setCustomPreCommandInterceptors(Lists.newArrayList( + new CustomLockProcessInstanceInterceptor(redisTemplate) + )); }; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java new file mode 100644 index 000000000..ed5aae60b --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java @@ -0,0 +1,12 @@ +package cn.axzo.workflow.core.engine.cmd; + +/** + * TODO + * + * @author wangli + * @since 2024/7/1 13:59 + */ +public abstract class AbstractCommand { + + public abstract String getProcessInstanceId(); +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java index 15a121697..0bd434a7a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java @@ -44,7 +44,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVir * @author wangli * @since 2024/1/2 18:19 */ -public class CustomAbortProcessInstanceCmd implements Command, Serializable { +public class CustomAbortProcessInstanceCmd extends AbstractCommand implements Command, Serializable { private final String processInstanceId; private final String tenantId; private final String reason; @@ -102,4 +102,12 @@ public class CustomAbortProcessInstanceCmd implements Command, Serializabl runtimeService.setVariable(task.getProcessInstanceId(), TASK_COMPLETE_OPERATION_TYPE + task.getId(), ABORTED); return null; } + + @Override + public String getProcessInstanceId() { + if (StringUtils.hasText(processInstanceId)) { + return processInstanceId; + } + return null; + } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index 9bdaabe5f..f891b67a4 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -10,6 +10,7 @@ import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.context.Context; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; @@ -38,7 +39,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @author wangli * @since 2024/1/4 15:50 */ -public class CustomApproveTaskCmd implements Command, Serializable { +public class CustomApproveTaskCmd extends AbstractCommand implements Command, Serializable { private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskCmd.class); private final String taskId; @@ -146,4 +147,17 @@ public class CustomApproveTaskCmd implements Command, Serializable { } } + @Override + public String getProcessInstanceId() { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(Context.getCommandContext()); + HistoricTaskInstanceQuery taskQuery = + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + + HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult(); + if (Objects.isNull(historicTaskInstance)) { + return null; + } + return historicTaskInstance.getProcessInstanceId(); + } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java index 93c447265..540378165 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.engine.cmd; +import cn.axzo.framework.context.validation.SpringValidator; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; @@ -12,6 +13,7 @@ import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.api.Task; +import org.springframework.util.StringUtils; import java.io.Serializable; import java.util.HashMap; @@ -41,7 +43,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVir * @author wangli * @since 2024/1/2 18:19 */ -public class CustomCancelProcessInstanceCmd implements Command, Serializable { +public class CustomCancelProcessInstanceCmd extends AbstractCommand implements Command, Serializable { private final String processInstanceId; private final String tenantId; private final String reason; @@ -102,4 +104,12 @@ public class CustomCancelProcessInstanceCmd implements Command, Serializab addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已撤回"); return null; } + + @Override + public String getProcessInstanceId() { + if (StringUtils.hasText(processInstanceId)) { + return processInstanceId; + } + return null; + } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index b1f559d6c..7b47c6c1d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -11,6 +11,7 @@ import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.context.Context; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; @@ -21,6 +22,7 @@ import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG; @@ -42,7 +44,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @author wangli * @since 2024/1/4 13:36 */ -public class CustomRejectionTaskCmd implements Command, Serializable { +public class CustomRejectionTaskCmd extends AbstractCommand implements Command, Serializable { private final String taskId; private final String advice; @@ -99,4 +101,18 @@ public class CustomRejectionTaskCmd implements Command, Serializable { .planOperation(new DeleteProcessInstanceOperation(commandContext, task.getProcessInstanceId(), extAxHiTaskInstService)); } + + @Override + public String getProcessInstanceId() { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(Context.getCommandContext()); + HistoricTaskInstanceQuery taskQuery = + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + + HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult(); + if (Objects.isNull(historicTaskInstance)) { + return null; + } + return historicTaskInstance.getProcessInstanceId(); + } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java new file mode 100644 index 000000000..cb9f25af6 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -0,0 +1,148 @@ +package cn.axzo.workflow.core.engine.interceptor; + +import cn.axzo.workflow.core.engine.cmd.AbstractCommand; +import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandConfig; +import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.connection.ReturnType; +import org.springframework.data.redis.core.RedisConnectionUtils; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.types.Expiration; + +import java.nio.charset.Charset; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * 增加一个拦截器,用来控制多个操作,不允许同时操作同一个实例 + * + * @author wangli + * @since 2024/7/1 13:51 + */ +public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterceptor { + private String key_prefix = "operation:processInstance:"; + /** + * 解锁脚本,原子操作 + */ + private static final String unlockScript = + "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" + + "then\n" + + " return redis.call(\"del\",KEYS[1])\n" + + "else\n" + + " return 0\n" + + "end"; + private static final Logger log = LoggerFactory.getLogger(CustomLockProcessInstanceInterceptor.class); + private final StringRedisTemplate redisTemplate; + + public CustomLockProcessInstanceInterceptor(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + @Override + public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { + if (AbstractCommand.class.isAssignableFrom(command.getClass())) { + AbstractCommand abstractCommand = (AbstractCommand) command; + String token = null; + try { + do { + token = getLock(abstractCommand.getProcessInstanceId(), 10 * 1000, 11 * 1000); + } while (Objects.isNull(token)); + return next.execute(config, command, commandExecutor); + } finally { + if (token != null) { + unlock(abstractCommand.getProcessInstanceId(), token); + } + } + } + return next.execute(config, command, commandExecutor); + } + + /** + * 加锁,有阻塞 + * + * @param name key的值 + * @param expire 过期时间 + * @param timeout 加锁执行超时时间 + * @return + */ + public String getLock(String name, long expire, long timeout) { + long startTime = System.currentTimeMillis(); //获取开始时间 + String token; + //规定的时间内,循环获取有值的token + do { + token = tryGetLock(name, expire); //获取秘钥Key + if (token == null) { + if ((System.currentTimeMillis() - startTime) > (timeout - 50)) + break; + try { + Thread.sleep(50); //try 50毫秒 per sec milliseconds + } catch (InterruptedException e) { + log.warn("getLock error: {}", e.getMessage(), e); + return null; + } + } + } while (token == null); + return token; + } + + /** + * 加锁,无阻塞 + * + * @param name 设置key + * @param expire + * @return + */ + public String tryGetLock(String name, long expire) { + //获取UUID值为value + String token = UUID.randomUUID().toString(); + RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); + RedisConnection conn = factory.getConnection(); + try { + Boolean result = conn.set(name.getBytes(Charset.forName("UTF-8")), //设置name为key + token.getBytes(Charset.forName("UTF-8")), //设置token为value +// Expiration.from(expire, TimeUnit.MILLISECONDS), //设置过期时间:MILLISECONDS毫秒 + Expiration.persistent(), + RedisStringCommands.SetOption.SET_IF_ABSENT); //如果name不存在创建 + if (result != null && result) + return token; + } finally { + RedisConnectionUtils.releaseConnection(conn, factory); + } + return null; + } + + /** + * 功能描述:使用Lua脚本解锁 + * + * @MethodName: unlock + * @MethodParam: [name, token] + * @Return: boolean + * @Author: yyalin + * @CreateDate: 2023/7/17 18:41 + */ + public boolean unlock(String name, String token) { + byte[][] keysAndArgs = new byte[2][]; + keysAndArgs[0] = name.getBytes(Charset.forName("UTF-8")); //lock_key + keysAndArgs[1] = token.getBytes(Charset.forName("UTF-8")); //token的值,也即唯一标识符 + RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); + RedisConnection conn = factory.getConnection(); + try { + Long result = (Long) conn.scriptingCommands().eval(unlockScript.getBytes(Charset.forName("UTF-8")), + ReturnType.INTEGER, 1, keysAndArgs); + if (result != null && result > 0) + return true; + } finally { + RedisConnectionUtils.releaseConnection(conn, factory); + } + return false; + } + + +} From 018c4bb9eb64f05729ab9039d537c323e7448453 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 15:17:36 +0800 Subject: [PATCH 190/210] =?UTF-8?q?hotfix/improve-batch-operation=20-=20?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=90=8C=E6=97=B6=E6=93=8D=E4=BD=9C=E5=90=8C?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/CustomLockProcessInstanceInterceptor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java index cb9f25af6..5906ff39f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -18,7 +18,6 @@ import org.springframework.data.redis.core.types.Expiration; import java.nio.charset.Charset; import java.util.Objects; import java.util.UUID; -import java.util.concurrent.TimeUnit; /** * 增加一个拦截器,用来控制多个操作,不允许同时操作同一个实例 @@ -27,7 +26,7 @@ import java.util.concurrent.TimeUnit; * @since 2024/7/1 13:51 */ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterceptor { - private String key_prefix = "operation:processInstance:"; + private static final String KEY_PREFIX = "operation:processInstance:"; /** * 解锁脚本,原子操作 */ @@ -52,7 +51,7 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce String token = null; try { do { - token = getLock(abstractCommand.getProcessInstanceId(), 10 * 1000, 11 * 1000); + token = getLock(KEY_PREFIX + abstractCommand.getProcessInstanceId(), 10 * 1000, 11 * 1000); } while (Objects.isNull(token)); return next.execute(config, command, commandExecutor); } finally { From 284ac47e7d1146e144a8c7a61befd0e21d21efad Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 15:39:01 +0800 Subject: [PATCH 191/210] =?UTF-8?q?update=20-=20=E5=B0=86=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E4=BB=BB=E5=8A=A1=E5=86=85=E6=AD=A3=E5=B8=B8=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E8=BF=9B=E8=A1=8C=E5=90=9E=E5=B9=B6,=20=E4=BD=86?= =?UTF-8?q?=E4=BB=8D=E7=84=B6=E8=AE=B0=E5=BD=95=E5=BC=82=E5=B8=B8=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomWorkflowEngineExceptionHandler.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/exception/handle/CustomWorkflowEngineExceptionHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/exception/handle/CustomWorkflowEngineExceptionHandler.java index 352b104ec..80ef948ed 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/exception/handle/CustomWorkflowEngineExceptionHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/exception/handle/CustomWorkflowEngineExceptionHandler.java @@ -19,15 +19,16 @@ public class CustomWorkflowEngineExceptionHandler implements AsyncRunnableExecut @Override public boolean handleException(JobServiceConfiguration jobServiceConfiguration, JobInfo job, Throwable e) { Throwable rootCause = getRootCause(e); - if (rootCause.getClass().isAssignableFrom(WorkflowEngineException.class)) { - WorkflowEngineException workflowEngineException = (WorkflowEngineException) rootCause; - if (Objects.equals(workflowEngineException.getCode(), "99806020")) { - log.info("AsyncApproveTaskJobHandler execute exception code: {} info: {}", - workflowEngineException.getCode(), rootCause.getMessage(), rootCause); - return true; - } - } - return false; +// if (rootCause.getClass().isAssignableFrom(WorkflowEngineException.class)) { +// WorkflowEngineException workflowEngineException = (WorkflowEngineException) rootCause; +// if (Objects.equals(workflowEngineException.getCode(), "99806020")) { +// log.info("AsyncApproveTaskJobHandler execute exception code: {} info: {}", +// workflowEngineException.getCode(), rootCause.getMessage(), rootCause); +// return true; +// } +// } + log.warn("Async Runnable Execution Exception: {}", rootCause.getMessage(), e); + return WorkflowEngineException.class.isAssignableFrom(rootCause.getClass()); } private Throwable getRootCause(Throwable throwable) { From 4b809512c668af1a5e4f25b52471c3862b7fa5f9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 15:58:40 +0800 Subject: [PATCH 192/210] =?UTF-8?q?update=20-=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=98=E6=9B=B4=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Changelog.md b/Changelog.md index 1ab9ece08..5e61a3ff6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,13 @@ # Change logs +### 1.4.0-SNAPSHOT + +> - 新增 workflow-engine-spring-boot-starter 组件,大幅简化业务方接入使用的难度。 +> - 在 Starter 中新增 MQ 监控功能,避免死信依赖运维。 +> - 优化发送待办时,提前判断是否有按钮,以及能否支持批量处理。 +> - 修复同一个实例下,多个人同时操作任务,可能导致数据库的 FK 异常等问题。 +> - 修复其他的一些小问题 + ### 1.3.3-SNAPSHOT > - 支持“政务”类型的模型管理。 From 959361af554396de4004d227db77626f261d691e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 20:31:35 +0800 Subject: [PATCH 193/210] =?UTF-8?q?update=20-=20=E6=9A=82=E6=97=B6?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=AE=9E=E4=BE=8B=20ID=20=E5=88=86=E5=B8=83?= =?UTF-8?q?=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/workflow/core/conf/FlowableConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 1860b1b7b..fe8f1ea90 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -97,7 +97,7 @@ public class FlowableConfiguration { new CustomAsyncRunnableExceptionExceptionHandler())); configuration.setCommandContextFactory(new CustomCommandContextFactory()); configuration.setCustomPreCommandInterceptors(Lists.newArrayList( - new CustomLockProcessInstanceInterceptor(redisTemplate) +// new CustomLockProcessInstanceInterceptor(redisTemplate) )); }; } From c81ff4e58da5af992ba731d64d068ca9d36a2379 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 20:45:10 +0800 Subject: [PATCH 194/210] =?UTF-8?q?update=20-=20=E6=9A=82=E6=97=B6?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=AE=9E=E4=BE=8B=20ID=20=E5=88=86=E5=B8=83?= =?UTF-8?q?=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/CustomLockProcessInstanceInterceptor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java index 5906ff39f..a96d5687d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -52,9 +52,11 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce try { do { token = getLock(KEY_PREFIX + abstractCommand.getProcessInstanceId(), 10 * 1000, 11 * 1000); + log.info(" threadName: {}, token: {}", Thread.currentThread().getName(), token); } while (Objects.isNull(token)); return next.execute(config, command, commandExecutor); } finally { + log.info("finally unlock threadName: {}, token: {}", Thread.currentThread().getName(), token); if (token != null) { unlock(abstractCommand.getProcessInstanceId(), token); } @@ -111,6 +113,10 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce RedisStringCommands.SetOption.SET_IF_ABSENT); //如果name不存在创建 if (result != null && result) return token; + } catch (Exception e) { + unlock(name, token); + log.warn("tryGetLock error: {}", e.getMessage(), e); + return null; } finally { RedisConnectionUtils.releaseConnection(conn, factory); } From 278d4d989d57b4d90dfb9d257cef060da4980730 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 20:49:49 +0800 Subject: [PATCH 195/210] =?UTF-8?q?update=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/workflow/core/conf/FlowableConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index fe8f1ea90..1860b1b7b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -97,7 +97,7 @@ public class FlowableConfiguration { new CustomAsyncRunnableExceptionExceptionHandler())); configuration.setCommandContextFactory(new CustomCommandContextFactory()); configuration.setCustomPreCommandInterceptors(Lists.newArrayList( -// new CustomLockProcessInstanceInterceptor(redisTemplate) + new CustomLockProcessInstanceInterceptor(redisTemplate) )); }; } From 439a2ceac511a3dbb9799df6e1b5d7d5d44a554f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 1 Jul 2024 20:55:30 +0800 Subject: [PATCH 196/210] =?UTF-8?q?update=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/CustomLockProcessInstanceInterceptor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java index a96d5687d..44294fc89 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -45,7 +45,7 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce } @Override - public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { + public final T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { if (AbstractCommand.class.isAssignableFrom(command.getClass())) { AbstractCommand abstractCommand = (AbstractCommand) command; String token = null; @@ -143,6 +143,10 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce ReturnType.INTEGER, 1, keysAndArgs); if (result != null && result > 0) return true; + } catch (Exception e) { + log.warn("unlock error: {}", e.getMessage(), e); +// unlock(name, token); + return false; } finally { RedisConnectionUtils.releaseConnection(conn, factory); } From 67865c8be0cef11e31fd640da50149e5426e6784 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 2 Jul 2024 09:41:00 +0800 Subject: [PATCH 197/210] =?UTF-8?q?update=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomLockProcessInstanceInterceptor.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java index 44294fc89..6638e1698 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.core.engine.interceptor; import cn.axzo.workflow.core.engine.cmd.AbstractCommand; +import liquibase.pro.packaged.T; import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandConfig; @@ -58,7 +59,7 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce } finally { log.info("finally unlock threadName: {}, token: {}", Thread.currentThread().getName(), token); if (token != null) { - unlock(abstractCommand.getProcessInstanceId(), token); + unlock(KEY_PREFIX + abstractCommand.getProcessInstanceId(), token); } } } @@ -141,16 +142,22 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce try { Long result = (Long) conn.scriptingCommands().eval(unlockScript.getBytes(Charset.forName("UTF-8")), ReturnType.INTEGER, 1, keysAndArgs); - if (result != null && result > 0) + if (result != null && result > 0) { return true; + } else { + throw new IllegalStateException("unLock ProcessInstance fail"); + } } catch (Exception e) { log.warn("unlock error: {}", e.getMessage(), e); -// unlock(name, token); - return false; + try { + Thread.sleep(1000L); + } catch (InterruptedException ex) { + // ignore + } + return unlock(name, token); } finally { RedisConnectionUtils.releaseConnection(conn, factory); } - return false; } From 8326f878e5084b98c52f7463b3fd13f075e57912 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 2 Jul 2024 09:48:02 +0800 Subject: [PATCH 198/210] =?UTF-8?q?update=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomLockProcessInstanceInterceptor.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java index 6638e1698..fedcdaa15 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -17,6 +17,7 @@ import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.types.Expiration; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.UUID; @@ -107,15 +108,18 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); RedisConnection conn = factory.getConnection(); try { - Boolean result = conn.set(name.getBytes(Charset.forName("UTF-8")), //设置name为key - token.getBytes(Charset.forName("UTF-8")), //设置token为value + Boolean result = conn.set(name.getBytes(StandardCharsets.UTF_8), //设置name为key + token.getBytes(StandardCharsets.UTF_8), //设置token为value // Expiration.from(expire, TimeUnit.MILLISECONDS), //设置过期时间:MILLISECONDS毫秒 Expiration.persistent(), RedisStringCommands.SetOption.SET_IF_ABSENT); //如果name不存在创建 - if (result != null && result) + log.info("tryGetLock result: {}", result); + if (Objects.isNull(result)) { + throw new IllegalStateException("tryGetLock processInstance fail"); + } + if (result) return token; } catch (Exception e) { - unlock(name, token); log.warn("tryGetLock error: {}", e.getMessage(), e); return null; } finally { @@ -142,11 +146,10 @@ public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterce try { Long result = (Long) conn.scriptingCommands().eval(unlockScript.getBytes(Charset.forName("UTF-8")), ReturnType.INTEGER, 1, keysAndArgs); - if (result != null && result > 0) { - return true; - } else { - throw new IllegalStateException("unLock ProcessInstance fail"); + if (Objects.isNull(result)) { + throw new IllegalStateException("unLock processInstance fail"); } + return result > 0; } catch (Exception e) { log.warn("unlock error: {}", e.getMessage(), e); try { From d8f428150c340ba48c1caeeffc3eaed42535f39c Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Tue, 2 Jul 2024 10:41:37 +0800 Subject: [PATCH 199/210] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E9=A2=84=E6=B5=8B=E6=B5=81=E7=A8=8B=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=BB=93=E6=9D=9F=E5=AF=BC=E8=87=B4=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomCarbonCopyUserSelectorCmd.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java index f43a8bb8b..3e5f736f7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java @@ -10,6 +10,7 @@ import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.CustomProperty; import org.flowable.bpmn.model.ServiceTask; import org.flowable.common.engine.impl.interceptor.Command; @@ -33,6 +34,7 @@ import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; @@ -45,6 +47,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDup * @author wangli * @since 18/03/2024 11:33 */ +@Slf4j public class CustomCarbonCopyUserSelectorCmd implements Command>, Serializable { private static final long serialVersionUID = 1L; @@ -97,6 +100,17 @@ public class CustomCarbonCopyUserSelectorCmd implements Command hisVarInst = processEngineConfiguration.getHistoryService().createHistoricVariableInstanceQuery() + .processInstanceId(processInstanceId) + .variableName(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + serviceTask.getId()).list(); + if (!CollectionUtils.isEmpty(hisVarInst)) { + return (List) hisVarInst.get(0).getValue(); + } + log.warn("executions is empty,get historic task assigner list empty,processInstanceId: {},serviceTaskId: {}", processInstanceId, serviceTask.getId()); + return Collections.emptyList(); + } List assigners = new ArrayList<>(); carbons.forEach(carbon -> { CarbonCopyObjectType carbonCopyObjectType = carbon.getCarbonCopyObjectType(); From fcbdd78ff1d06a6958a803d625768cec9ca0eb8f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 2 Jul 2024 11:06:48 +0800 Subject: [PATCH 200/210] =?UTF-8?q?update=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/workflow/core/conf/FlowableConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 1860b1b7b..fe8f1ea90 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -97,7 +97,7 @@ public class FlowableConfiguration { new CustomAsyncRunnableExceptionExceptionHandler())); configuration.setCommandContextFactory(new CustomCommandContextFactory()); configuration.setCustomPreCommandInterceptors(Lists.newArrayList( - new CustomLockProcessInstanceInterceptor(redisTemplate) +// new CustomLockProcessInstanceInterceptor(redisTemplate) )); }; } From 8a0affbf44b87a02b3ba3918130cf62a22c4f741 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 2 Jul 2024 18:20:29 +0800 Subject: [PATCH 201/210] =?UTF-8?q?update=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E8=AF=BB=20API=20=E7=9A=84=E9=98=B2=E9=87=8D=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/bpmn/BpmnProcessInstanceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index af74fb7ef..173adfd8b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.history.HistoricProcessInstance; +import org.springframework.cache.annotation.CachePut; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -268,7 +269,6 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { @Operation(summary = "获取指定流程实例的流程变量") @GetMapping("/cooperation-org") @Override - @RepeatSubmit public CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable String tenantId) { HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId, From 78cf58423d95e0f5b980bc4d7cdec1464bdb2e3d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 2 Jul 2024 19:04:01 +0800 Subject: [PATCH 202/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/conf/FlowableConfiguration.java | 3 +- .../CustomLockProcessInstanceInterceptor.java | 193 +++++------------- 2 files changed, 56 insertions(+), 140 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index fe8f1ea90..769d3651a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -23,6 +23,7 @@ import com.alibaba.cloud.nacos.NacosServiceManager; import com.google.common.collect.Lists; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.common.engine.impl.history.HistoryLevel; +import org.flowable.common.engine.impl.interceptor.RetryInterceptor; import org.flowable.form.spring.SpringFormEngineConfiguration; import org.flowable.job.service.JobProcessor; import org.flowable.spring.SpringProcessEngineConfiguration; @@ -97,7 +98,7 @@ public class FlowableConfiguration { new CustomAsyncRunnableExceptionExceptionHandler())); configuration.setCommandContextFactory(new CustomCommandContextFactory()); configuration.setCustomPreCommandInterceptors(Lists.newArrayList( -// new CustomLockProcessInstanceInterceptor(redisTemplate) + new CustomLockProcessInstanceInterceptor() )); }; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java index fedcdaa15..f15ab3040 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java @@ -1,25 +1,12 @@ package cn.axzo.workflow.core.engine.interceptor; -import cn.axzo.workflow.core.engine.cmd.AbstractCommand; -import liquibase.pro.packaged.T; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.exceptions.PersistenceException; +import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandConfig; import org.flowable.common.engine.impl.interceptor.CommandExecutor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.RedisStringCommands; -import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.core.RedisConnectionUtils; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.core.types.Expiration; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Objects; -import java.util.UUID; /** * 增加一个拦截器,用来控制多个操作,不允许同时操作同一个实例 @@ -27,141 +14,69 @@ import java.util.UUID; * @author wangli * @since 2024/7/1 13:51 */ +@Slf4j public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterceptor { - private static final String KEY_PREFIX = "operation:processInstance:"; - /** - * 解锁脚本,原子操作 - */ - private static final String unlockScript = - "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" - + "then\n" - + " return redis.call(\"del\",KEYS[1])\n" - + "else\n" - + " return 0\n" - + "end"; - private static final Logger log = LoggerFactory.getLogger(CustomLockProcessInstanceInterceptor.class); - private final StringRedisTemplate redisTemplate; - public CustomLockProcessInstanceInterceptor(StringRedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } + protected int numOfRetries = 3; + protected int waitTimeInMs = 50; + protected int waitIncreaseFactor = 5; @Override - public final T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { - if (AbstractCommand.class.isAssignableFrom(command.getClass())) { - AbstractCommand abstractCommand = (AbstractCommand) command; - String token = null; - try { - do { - token = getLock(KEY_PREFIX + abstractCommand.getProcessInstanceId(), 10 * 1000, 11 * 1000); - log.info(" threadName: {}, token: {}", Thread.currentThread().getName(), token); - } while (Objects.isNull(token)); - return next.execute(config, command, commandExecutor); - } finally { - log.info("finally unlock threadName: {}, token: {}", Thread.currentThread().getName(), token); - if (token != null) { - unlock(KEY_PREFIX + abstractCommand.getProcessInstanceId(), token); - } - } - } - return next.execute(config, command, commandExecutor); - } + public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { + long waitTime = waitTimeInMs; + int failedAttempts = 0; - /** - * 加锁,有阻塞 - * - * @param name key的值 - * @param expire 过期时间 - * @param timeout 加锁执行超时时间 - * @return - */ - public String getLock(String name, long expire, long timeout) { - long startTime = System.currentTimeMillis(); //获取开始时间 - String token; - //规定的时间内,循环获取有值的token do { - token = tryGetLock(name, expire); //获取秘钥Key - if (token == null) { - if ((System.currentTimeMillis() - startTime) > (timeout - 50)) - break; - try { - Thread.sleep(50); //try 50毫秒 per sec milliseconds - } catch (InterruptedException e) { - log.warn("getLock error: {}", e.getMessage(), e); - return null; - } + if (failedAttempts > 0) { + log.warn("Waiting for {}ms before retrying the command.", waitTime); + waitBeforeRetry(waitTime); + waitTime *= waitIncreaseFactor; } - } while (token == null); - return token; - } - /** - * 加锁,无阻塞 - * - * @param name 设置key - * @param expire - * @return - */ - public String tryGetLock(String name, long expire) { - //获取UUID值为value - String token = UUID.randomUUID().toString(); - RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); - RedisConnection conn = factory.getConnection(); - try { - Boolean result = conn.set(name.getBytes(StandardCharsets.UTF_8), //设置name为key - token.getBytes(StandardCharsets.UTF_8), //设置token为value -// Expiration.from(expire, TimeUnit.MILLISECONDS), //设置过期时间:MILLISECONDS毫秒 - Expiration.persistent(), - RedisStringCommands.SetOption.SET_IF_ABSENT); //如果name不存在创建 - log.info("tryGetLock result: {}", result); - if (Objects.isNull(result)) { - throw new IllegalStateException("tryGetLock processInstance fail"); - } - if (result) - return token; - } catch (Exception e) { - log.warn("tryGetLock error: {}", e.getMessage(), e); - return null; - } finally { - RedisConnectionUtils.releaseConnection(conn, factory); - } - return null; - } - - /** - * 功能描述:使用Lua脚本解锁 - * - * @MethodName: unlock - * @MethodParam: [name, token] - * @Return: boolean - * @Author: yyalin - * @CreateDate: 2023/7/17 18:41 - */ - public boolean unlock(String name, String token) { - byte[][] keysAndArgs = new byte[2][]; - keysAndArgs[0] = name.getBytes(Charset.forName("UTF-8")); //lock_key - keysAndArgs[1] = token.getBytes(Charset.forName("UTF-8")); //token的值,也即唯一标识符 - RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); - RedisConnection conn = factory.getConnection(); - try { - Long result = (Long) conn.scriptingCommands().eval(unlockScript.getBytes(Charset.forName("UTF-8")), - ReturnType.INTEGER, 1, keysAndArgs); - if (Objects.isNull(result)) { - throw new IllegalStateException("unLock processInstance fail"); - } - return result > 0; - } catch (Exception e) { - log.warn("unlock error: {}", e.getMessage(), e); try { - Thread.sleep(1000L); - } catch (InterruptedException ex) { - // ignore + + // try to execute the command + return next.execute(config, command, commandExecutor); + + } catch (PersistenceException e) { + log.error("Caught persistence exception: {}", e.getMessage(), e); } - return unlock(name, token); - } finally { - RedisConnectionUtils.releaseConnection(conn, factory); + + failedAttempts++; + } while (failedAttempts <= numOfRetries); + + throw new FlowableException(numOfRetries + " retries failed with FlowableOptimisticLockingException. Giving up."); + } + + protected void waitBeforeRetry(long waitTime) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + log.error("I am interrupted while waiting for a retry."); } } + public void setNumOfRetries(int numOfRetries) { + this.numOfRetries = numOfRetries; + } + public void setWaitIncreaseFactor(int waitIncreaseFactor) { + this.waitIncreaseFactor = waitIncreaseFactor; + } + + public void setWaitTimeInMs(int waitTimeInMs) { + this.waitTimeInMs = waitTimeInMs; + } + + public int getNumOfRetries() { + return numOfRetries; + } + + public int getWaitIncreaseFactor() { + return waitIncreaseFactor; + } + + public int getWaitTimeInMs() { + return waitTimeInMs; + } } From 5334b67e644930291e4a19bd1f7ae8845c00d439 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 10:47:22 +0800 Subject: [PATCH 203/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/code/FlowableEngineRespCode.java | 2 + .../workflow/core/common/utils/TraceUtil.java | 24 +++++ .../core/conf/FlowableConfiguration.java | 6 +- .../core/engine/cmd/AbstractCommand.java | 7 +- .../CustomAbortProcessInstanceAsyncCmd.java | 10 +- .../cmd/CustomAbortProcessInstanceCmd.java | 20 ++-- .../engine/cmd/CustomApproveTaskAsyncCmd.java | 10 +- .../core/engine/cmd/CustomApproveTaskCmd.java | 30 +++--- .../CustomBizSpecifyAssigneeToTaskCmd.java | 13 ++- .../CustomCancelProcessInstanceAsyncCmd.java | 10 +- .../cmd/CustomCancelProcessInstanceCmd.java | 20 ++-- .../cmd/CustomCarbonCopyUserSelectorCmd.java | 13 ++- .../core/engine/cmd/CustomCommentTaskCmd.java | 16 +++- .../cmd/CustomCompleteDummyTaskCmd.java | 16 +++- .../CustomCountersignUserTaskAsyncCmd.java | 11 ++- .../cmd/CustomCountersignUserTaskCmd.java | 18 +++- .../engine/cmd/CustomCreateDummyTaskCmd.java | 16 +++- .../CustomForecastUserTaskAssigneeCmd.java | 12 ++- ...ustomNoticeDestinationUserSelectorCmd.java | 15 ++- .../cmd/CustomRejectionTaskAsyncCmd.java | 11 ++- .../engine/cmd/CustomRejectionTaskCmd.java | 28 +++--- .../cmd/CustomTransferUserTaskAsyncCmd.java | 12 ++- .../engine/cmd/CustomTransferUserTaskCmd.java | 16 +++- .../CustomLockProcessInstanceInterceptor.java | 82 ----------------- .../interceptor/CustomRetryInterceptor.java | 92 +++++++++++++++++++ .../support/ExpressionConditionCmd.java | 14 ++- .../engine/impl/cmd/CreateAttachmentCmd.java | 21 ++++- workflow-engine-server/pom.xml | 8 +- .../common/filter/HttpTraceLogFilter.java | 18 +++- 29 files changed, 406 insertions(+), 165 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/TraceUtil.java delete mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java index 91443883f..c712329cb 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java @@ -18,6 +18,8 @@ public enum FlowableEngineRespCode implements IModuleRespCode { ENGINE_USER_TASK_TYPE_NOT_SUPPORT("003", "审批指定方式暂不支持"), ENGINE_USER_TASK_PARAM_ERROR("004", "构建后的查询审批人入参为空. 任务节点【nodeId:{}】, 该节点选择的\"审批人所在范围\"是:【{}】,请检查 cooperationOrg 参数"), ENGINE_NOTICE_CUSTOM_FLOW_ELEMENT_ERROR("005", "查询通知目标用户前参数发生异常,未获取到 WorkspaceType"), + ENGINE_ASYNC_COMMAND_EXECUTION_ERROR("006", "引擎出现 SQL 相关异常, 异常信息:【{}】"), + ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现 PersistenceException, 将放弃"), ; private String code; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/TraceUtil.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/TraceUtil.java new file mode 100644 index 000000000..86fd83f41 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/TraceUtil.java @@ -0,0 +1,24 @@ +package cn.axzo.workflow.core.common.utils; + +import org.slf4j.MDC; +import org.springframework.util.StringUtils; + +import static cn.axzo.workflow.common.constant.LogFieldConstants.X_REQUEST_ID; +import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; + +/** + * 获取 TraceId + * + * @author wangli + * @since 2024/7/3 10:14 + */ +public final class TraceUtil { + + private TraceUtil() { + } + + public static String traceId() { + String xRequestId = MDC.get(X_REQUEST_ID); + return StringUtils.hasText(xRequestId) ? xRequestId : MDC.get(CTX_LOG_ID_MDC); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 769d3651a..ed8ec8a02 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -3,7 +3,7 @@ package cn.axzo.workflow.core.conf; import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory; import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory; import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator; -import cn.axzo.workflow.core.engine.interceptor.CustomLockProcessInstanceInterceptor; +import cn.axzo.workflow.core.engine.interceptor.CustomRetryInterceptor; import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler; import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler; @@ -23,7 +23,6 @@ import com.alibaba.cloud.nacos.NacosServiceManager; import com.google.common.collect.Lists; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.common.engine.impl.history.HistoryLevel; -import org.flowable.common.engine.impl.interceptor.RetryInterceptor; import org.flowable.form.spring.SpringFormEngineConfiguration; import org.flowable.job.service.JobProcessor; import org.flowable.spring.SpringProcessEngineConfiguration; @@ -32,7 +31,6 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import java.time.Duration; @@ -98,7 +96,7 @@ public class FlowableConfiguration { new CustomAsyncRunnableExceptionExceptionHandler())); configuration.setCommandContextFactory(new CustomCommandContextFactory()); configuration.setCustomPreCommandInterceptors(Lists.newArrayList( - new CustomLockProcessInstanceInterceptor() + new CustomRetryInterceptor() )); }; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java index ed5aae60b..491c72cb8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java @@ -1,12 +1,15 @@ package cn.axzo.workflow.core.engine.cmd; + +import org.flowable.common.engine.impl.interceptor.Command; + /** * TODO * * @author wangli * @since 2024/7/1 13:59 */ -public abstract class AbstractCommand { +public abstract class AbstractCommand implements Command { - public abstract String getProcessInstanceId(); + public abstract String paramToJsonString(); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java index 4dbc65b81..ec87d66fa 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java @@ -4,7 +4,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbo import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler; import cn.hutool.json.JSONUtil; -import org.flowable.common.engine.impl.interceptor.Command; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; import org.flowable.engine.history.HistoricProcessInstance; @@ -23,7 +23,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_ABORT; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; -public class CustomAbortProcessInstanceAsyncCmd implements Command, Serializable { +public class CustomAbortProcessInstanceAsyncCmd extends AbstractCommand implements Serializable { private final BpmnProcessInstanceAbortDTO dto; @@ -31,6 +31,11 @@ public class CustomAbortProcessInstanceAsyncCmd implements Command, Serial this.dto = dto; } + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + @Override public Void execute(CommandContext commandContext) { String processInstanceId = dto.getProcessInstanceId(); @@ -80,4 +85,5 @@ public class CustomAbortProcessInstanceAsyncCmd implements Command, Serial jobService.createAsyncJob(job, false); jobService.scheduleAsyncJob(job); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java index 0bd434a7a..91020386c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java @@ -4,6 +4,8 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import com.alibaba.fastjson.JSON; +import liquibase.pro.packaged.V; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; @@ -44,7 +46,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVir * @author wangli * @since 2024/1/2 18:19 */ -public class CustomAbortProcessInstanceCmd extends AbstractCommand implements Command, Serializable { +public class CustomAbortProcessInstanceCmd extends AbstractCommand implements Serializable { private final String processInstanceId; private final String tenantId; private final String reason; @@ -58,6 +60,15 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand implements Co this.extAxHiTaskInstService = extAxHiTaskInstService; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("tenantId", tenantId); + params.put("reason", reason); + return JSON.toJSONString(params); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -103,11 +114,4 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand implements Co return null; } - @Override - public String getProcessInstanceId() { - if (StringUtils.hasText(processInstanceId)) { - return processInstanceId; - } - return null; - } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java index 0f5d57be6..8c23dc946 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.TaskService; @@ -18,6 +19,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; @@ -28,7 +31,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @author wangli * @since 2024/1/4 15:50 */ -public class CustomApproveTaskAsyncCmd implements Command, Serializable { +public class CustomApproveTaskAsyncCmd extends AbstractCommand implements Serializable { private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskAsyncCmd.class); private final BpmnTaskAuditDTO dto; @@ -37,6 +40,11 @@ public class CustomApproveTaskAsyncCmd implements Command, Serializable { this.dto = dto; } + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index f891b67a4..427be70d2 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -21,7 +22,9 @@ import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; @@ -39,7 +42,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @author wangli * @since 2024/1/4 15:50 */ -public class CustomApproveTaskCmd extends AbstractCommand implements Command, Serializable { +public class CustomApproveTaskCmd extends AbstractCommand implements Serializable { private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskCmd.class); private final String taskId; @@ -63,6 +66,18 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Command nodeTypes; + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("taskId", taskId); + params.put("advice", advice); + params.put("operationDesc", operationDesc); + params.put("attachmentList", JSON.toJSONString(attachmentList)); + params.put("approver", JSON.toJSONString(approver)); + params.put("nextApprover", JSON.toJSONString(nextApprover)); + params.put("nodeTypes", JSON.toJSONString(nodeTypes)); + return JSON.toJSONString(params); + } public CustomApproveTaskCmd(BpmnTaskAuditDTO dto) { this(dto, null); @@ -147,17 +162,4 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Command, Serializable { +public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand implements Serializable { private final String executionId; private final List addedAssigners; @@ -41,6 +44,14 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command, Seri this.addedAssigners = addedAssigners; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("executionId", executionId); + params.put("addedAssigners", addedAssigners); + return JSON.toJSONString(params); + } + @Override public Boolean execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java index b99ec73f3..38e8174f8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java @@ -5,7 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceHandler; import cn.hutool.json.JSONUtil; -import org.flowable.common.engine.impl.interceptor.Command; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; import org.flowable.engine.history.HistoricProcessInstance; @@ -23,7 +23,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_CANCEL; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; -public class CustomCancelProcessInstanceAsyncCmd implements Command, Serializable { +public class CustomCancelProcessInstanceAsyncCmd extends AbstractCommand implements Serializable { private final BpmnProcessInstanceCancelDTO dto; @@ -31,6 +31,11 @@ public class CustomCancelProcessInstanceAsyncCmd implements Command, Seria this.dto = dto; } + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + @Override public Void execute(CommandContext commandContext) { String processInstanceId = dto.getProcessInstanceId(), tenantId = dto.getTenantId(); @@ -81,4 +86,5 @@ public class CustomCancelProcessInstanceAsyncCmd implements Command, Seria jobService.createAsyncJob(job, false); jobService.scheduleAsyncJob(job); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java index 540378165..500a3a83b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; @@ -43,7 +44,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVir * @author wangli * @since 2024/1/2 18:19 */ -public class CustomCancelProcessInstanceCmd extends AbstractCommand implements Command, Serializable { +public class CustomCancelProcessInstanceCmd extends AbstractCommand implements Serializable { private final String processInstanceId; private final String tenantId; private final String reason; @@ -60,6 +61,16 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand implements C this.extAxHiTaskInstService = extAxHiTaskInstService; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("tenantId", tenantId); + params.put("reason", reason); + params.put("initiator", initiator); + return JSON.toJSONString(params); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -105,11 +116,4 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand implements C return null; } - @Override - public String getProcessInstanceId() { - if (StringUtils.hasText(processInstanceId)) { - return processInstanceId; - } - return null; - } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java index 3e5f736f7..8e126d1a2 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCarbonCopyUserSelectorCmd.java @@ -28,6 +28,7 @@ import org.springframework.util.CollectionUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -48,7 +49,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDup * @since 18/03/2024 11:33 */ @Slf4j -public class CustomCarbonCopyUserSelectorCmd implements Command>, Serializable { +public class CustomCarbonCopyUserSelectorCmd extends AbstractCommand> implements Serializable { private static final long serialVersionUID = 1L; private final String processInstanceId; @@ -86,6 +87,15 @@ public class CustomCarbonCopyUserSelectorCmd implements Command params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("carbons", carbons); + params.put("serviceVersion", serviceVersion); + return JSON.toJSONString(params); + } + @Override public List execute(CommandContext commandContext) { if (CollectionUtils.isEmpty(carbons)) { @@ -224,5 +234,4 @@ public class CustomCarbonCopyUserSelectorCmd implements Command, Serializable { +public class CustomCommentTaskCmd extends AbstractCommand implements Serializable { private final String processInstanceId; private final BpmnTaskDelegateAssigner operator; private final String comment; @@ -63,6 +66,17 @@ public class CustomCommentTaskCmd implements Command, Serializable { this.extAxHiTaskInstService = extAxHiTaskInstService; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("operator", operator); + params.put("comment", comment); + params.put("commentExt", commentExt); + params.put("attachmentList", attachmentList); + return JSON.toJSONString(params); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java index 6a9f920af..a00361cbf 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -16,7 +17,9 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; @@ -30,7 +33,7 @@ import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.DUMMY_TASK_NOT_ * @author wangli * @since 2023/12/27 11:24 */ -public class CustomCompleteDummyTaskCmd implements Command, Serializable { +public class CustomCompleteDummyTaskCmd extends AbstractCommand implements Serializable { private final String processInstanceId; private final String taskId; private final String flowNodeName; @@ -46,6 +49,16 @@ public class CustomCompleteDummyTaskCmd implements Command, Serializable { this.extAxHiTaskInstService = extAxHiTaskInstService; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("taskId", taskId); + params.put("flowNodeName", flowNodeName); + params.put("operationDesc", operationDesc); + return JSON.toJSONString(params); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -93,4 +106,5 @@ public class CustomCompleteDummyTaskCmd implements Command, Serializable { taskService.setOwner(i.getId(), null); }); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskAsyncCmd.java index 81956e9e7..f347c124d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskAsyncCmd.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler; import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.TaskService; @@ -16,17 +17,24 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated; -public class CustomCountersignUserTaskAsyncCmd implements Command, Serializable { +public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand implements Serializable { private final BpmnTaskCountersignDTO dto; public CustomCountersignUserTaskAsyncCmd(BpmnTaskCountersignDTO dto) { this.dto = dto; } + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -66,4 +74,5 @@ public class CustomCountersignUserTaskAsyncCmd implements Command, Seriali jobService.createAsyncJob(job, false); jobService.scheduleAsyncJob(job); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java index 329b022cf..877cad88d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -19,7 +20,9 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; @@ -39,7 +42,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @since 2023/12/25 14:05 */ @Slf4j -public class CustomCountersignUserTaskCmd implements Command, Serializable { +public class CustomCountersignUserTaskCmd extends AbstractCommand implements Serializable { private final BpmnCountersignTypeEnum countersignType; private final String originTaskId; @@ -62,6 +65,18 @@ public class CustomCountersignUserTaskCmd implements Command, Serializable this.extAxHiTaskInstService = extAxHiTaskInstService; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("countersignType", countersignType.getType()); + params.put("originTaskId", originTaskId); + params.put("originTaskAssignee", originTaskAssignee); + params.put("advice", advice); + params.put("attachmentList", JSON.toJSONString(attachmentList)); + params.put("targetTaskAssigneeList", JSON.toJSONString(targetTaskAssigneeList)); + return JSON.toJSONString(params); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -139,4 +154,5 @@ public class CustomCountersignUserTaskCmd implements Command, Serializable addComment(commandContext, virtualTask, COMMENT_TYPE_OPERATION_DESC, message.toString()); batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, originTaskAssignee); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCreateDummyTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCreateDummyTaskCmd.java index ba6cda820..f1973b35b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCreateDummyTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCreateDummyTaskCmd.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.cfg.IdGenerator; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.Command; @@ -21,7 +22,9 @@ import org.springframework.util.CollectionUtils; import java.io.Serializable; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; @@ -41,7 +44,7 @@ import static org.flowable.task.api.Task.DEFAULT_PRIORITY; * @author wangli * @since 2023/12/27 10:21 */ -public class CustomCreateDummyTaskCmd implements Command, Serializable { +public class CustomCreateDummyTaskCmd extends AbstractCommand implements Serializable { private final String processInstanceId; private final String flowNodeName; private final String operationDesc; @@ -57,6 +60,16 @@ public class CustomCreateDummyTaskCmd implements Command, Serializable { this.extAxHiTaskInstService = extAxHiTaskInstService; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("flowNodeName", flowNodeName); + params.put("operationDesc", operationDesc); + params.put("operator", operator); + return JSON.toJSONString(params); + } + /** * 在同一个实例下,不允许创建多个执行中的虚拟任务节点 * @@ -139,4 +152,5 @@ public class CustomCreateDummyTaskCmd implements Command, Serializable { }); } } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomForecastUserTaskAssigneeCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomForecastUserTaskAssigneeCmd.java index bb6070b5c..a17379858 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomForecastUserTaskAssigneeCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomForecastUserTaskAssigneeCmd.java @@ -19,7 +19,9 @@ import org.springframework.util.CollectionUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify; @@ -30,7 +32,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove * @since 2023/12/11 17:56 */ @Slf4j -public class CustomForecastUserTaskAssigneeCmd implements Command>, Serializable { +public class CustomForecastUserTaskAssigneeCmd extends AbstractCommand> implements Serializable { private final String processInstanceId; private final UserTask userTask; private final EngineExecutionStartListener engineExecutionStartListener; @@ -42,6 +44,13 @@ public class CustomForecastUserTaskAssigneeCmd implements Command params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + return JSON.toJSONString(params); + } + @Override public List execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -81,4 +90,5 @@ public class CustomForecastUserTaskAssigneeCmd implements Command>, Serializable { +public class CustomNoticeDestinationUserSelectorCmd extends AbstractCommand> implements Serializable { private static final long serialVersionUID = 1L; private final EngineExecutionStartListener engineExecutionStartListener; private final BpmnHistoricTaskInstanceConverter historicTaskInstanceConverter; @@ -63,6 +64,17 @@ public class CustomNoticeDestinationUserSelectorCmd implements Command params = new HashMap<>(); + params.put("serviceVersion", serviceVersion); + params.put("workspaceType", workspaceType); + params.put("noticeProperty", noticeProperty); + params.put("processInstanceId", processInstanceId); + params.put("initiator", initiator); + return JSON.toJSONString(params); + } + @Override public List execute(CommandContext commandContext) { if (!noticeProperty.getSendMessage()) { @@ -170,5 +182,4 @@ public class CustomNoticeDestinationUserSelectorCmd implements Command, Serializable { +public class CustomRejectionTaskAsyncCmd extends AbstractCommand implements Serializable { private final BpmnTaskAuditDTO dto; public CustomRejectionTaskAsyncCmd(BpmnTaskAuditDTO dto) { this.dto = dto; } + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -69,4 +75,5 @@ public class CustomRejectionTaskAsyncCmd implements Command, Serializable jobService.createAsyncJob(job, false); jobService.scheduleAsyncJob(job); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index 7b47c6c1d..610d2df65 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -6,7 +6,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; -import org.flowable.common.engine.impl.interceptor.Command; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; @@ -44,7 +44,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @author wangli * @since 2024/1/4 13:36 */ -public class CustomRejectionTaskCmd extends AbstractCommand implements Command, Serializable { +public class CustomRejectionTaskCmd extends AbstractCommand implements Serializable { private final String taskId; private final String advice; @@ -62,6 +62,17 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Command params = new HashMap<>(); + params.put("taskId", taskId); + params.put("advice", advice); + params.put("attachmentList", attachmentList); + params.put("approver", approver); + params.put("nodeTypes", nodeTypes); + return JSON.toJSONString(params); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = @@ -102,17 +113,4 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Command, Serializable { +public class CustomTransferUserTaskAsyncCmd extends AbstractCommand implements Serializable { private final BpmnTaskTransferDTO dto; @@ -32,6 +34,11 @@ public class CustomTransferUserTaskAsyncCmd implements Command, Serializab this.dto = dto; } + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); @@ -65,4 +72,5 @@ public class CustomTransferUserTaskAsyncCmd implements Command, Serializab jobService.createAsyncJob(job, false); jobService.scheduleAsyncJob(job); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java index 18c558946..5cf121307 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.Command; @@ -18,7 +19,9 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.util.StringUtils; import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -43,7 +46,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @author wangli * @since 2023/12/22 10:22 */ -public class CustomTransferUserTaskCmd implements Command, Serializable { +public class CustomTransferUserTaskCmd extends AbstractCommand implements Serializable { private final String originTaskId; private final BpmnTaskDelegateAssigner originTaskAssignee; @@ -60,6 +63,16 @@ public class CustomTransferUserTaskCmd implements Command, Serializable { this.targetTaskAssignee = targetTaskAssignee; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("originTaskId", originTaskId); + params.put("originTaskAssignee", originTaskAssignee); + params.put("advice", advice); + params.put("attachmentList", attachmentList); + params.put("targetTaskAssignee", targetTaskAssignee); + return JSON.toJSONString(params); + } @Override public Void execute(CommandContext commandContext) { @@ -125,4 +138,5 @@ public class CustomTransferUserTaskCmd implements Command, Serializable { INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), originAssingeeList); } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java deleted file mode 100644 index f15ab3040..000000000 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomLockProcessInstanceInterceptor.java +++ /dev/null @@ -1,82 +0,0 @@ -package cn.axzo.workflow.core.engine.interceptor; - -import lombok.extern.slf4j.Slf4j; -import org.apache.ibatis.exceptions.PersistenceException; -import org.flowable.common.engine.api.FlowableException; -import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor; -import org.flowable.common.engine.impl.interceptor.Command; -import org.flowable.common.engine.impl.interceptor.CommandConfig; -import org.flowable.common.engine.impl.interceptor.CommandExecutor; - -/** - * 增加一个拦截器,用来控制多个操作,不允许同时操作同一个实例 - * - * @author wangli - * @since 2024/7/1 13:51 - */ -@Slf4j -public class CustomLockProcessInstanceInterceptor extends AbstractCommandInterceptor { - - protected int numOfRetries = 3; - protected int waitTimeInMs = 50; - protected int waitIncreaseFactor = 5; - - @Override - public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { - long waitTime = waitTimeInMs; - int failedAttempts = 0; - - do { - if (failedAttempts > 0) { - log.warn("Waiting for {}ms before retrying the command.", waitTime); - waitBeforeRetry(waitTime); - waitTime *= waitIncreaseFactor; - } - - try { - - // try to execute the command - return next.execute(config, command, commandExecutor); - - } catch (PersistenceException e) { - log.error("Caught persistence exception: {}", e.getMessage(), e); - } - - failedAttempts++; - } while (failedAttempts <= numOfRetries); - - throw new FlowableException(numOfRetries + " retries failed with FlowableOptimisticLockingException. Giving up."); - } - - protected void waitBeforeRetry(long waitTime) { - try { - Thread.sleep(waitTime); - } catch (InterruptedException e) { - log.error("I am interrupted while waiting for a retry."); - } - } - - public void setNumOfRetries(int numOfRetries) { - this.numOfRetries = numOfRetries; - } - - public void setWaitIncreaseFactor(int waitIncreaseFactor) { - this.waitIncreaseFactor = waitIncreaseFactor; - } - - public void setWaitTimeInMs(int waitTimeInMs) { - this.waitTimeInMs = waitTimeInMs; - } - - public int getNumOfRetries() { - return numOfRetries; - } - - public int getWaitIncreaseFactor() { - return waitIncreaseFactor; - } - - public int getWaitTimeInMs() { - return waitTimeInMs; - } -} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java new file mode 100644 index 000000000..62094a5c0 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -0,0 +1,92 @@ +package cn.axzo.workflow.core.engine.interceptor; + +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.common.utils.TraceUtil; +import cn.axzo.workflow.core.engine.cmd.AbstractCommand; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.exceptions.PersistenceException; +import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandConfig; +import org.flowable.common.engine.impl.interceptor.CommandExecutor; + +import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_ASYNC_COMMAND_EXECUTION_ERROR; +import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP; + +/** + * 基于 RetryInterceptor 的命令重试拦截器, 本意想用来处理多人同时操作同一个任务, 但会存在超过重试次数后,会丢弃原有的命令. + * + * @author wangli + * @since 2024/7/1 13:51 + */ +@Slf4j +public class CustomRetryInterceptor extends AbstractCommandInterceptor { + + protected int numOfRetries = 3; + protected int waitTimeInMs = 60; + protected int waitIncreaseFactor = 5; + + @Override + public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { + try { + long waitTime = waitTimeInMs; + int failedAttempts = 0; + do { + if (failedAttempts > 0) { + log.warn("Waiting for {}ms before retrying the command.", waitTime); + waitBeforeRetry(waitTime); + waitTime *= waitIncreaseFactor; + } + + try { + // try to execute the command + if (AbstractCommand.class.isAssignableFrom(command.getClass())) { + log.info("traceId:{} Executing command params: {}", TraceUtil.traceId(), + ((AbstractCommand) command).paramToJsonString()); + } + return next.execute(config, command, commandExecutor); + + } catch (PersistenceException e) { + log.warn("Caught persistence exception: {}", e.getMessage(), e); + } + + failedAttempts++; + } while (failedAttempts <= numOfRetries); + throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries)); + } catch (Throwable e) { + throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_ERROR, e.getMessage()); + } + } + + protected void waitBeforeRetry(long waitTime) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + log.warn("I am interrupted while waiting for a retry."); + } + } + + public void setNumOfRetries(int numOfRetries) { + this.numOfRetries = numOfRetries; + } + + public void setWaitIncreaseFactor(int waitIncreaseFactor) { + this.waitIncreaseFactor = waitIncreaseFactor; + } + + public void setWaitTimeInMs(int waitTimeInMs) { + this.waitTimeInMs = waitTimeInMs; + } + + public int getNumOfRetries() { + return numOfRetries; + } + + public int getWaitIncreaseFactor() { + return waitIncreaseFactor; + } + + public int getWaitTimeInMs() { + return waitTimeInMs; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/ExpressionConditionCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/ExpressionConditionCmd.java index 672db4e0a..54c7080b3 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/ExpressionConditionCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/ExpressionConditionCmd.java @@ -1,7 +1,9 @@ package cn.axzo.workflow.core.service.support; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.engine.cmd.AbstractCommand; import cn.azxo.framework.common.utils.StringUtils; +import com.alibaba.fastjson.JSON; import org.flowable.common.engine.api.delegate.Expression; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -10,6 +12,8 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.persistence.entity.ExecutionEntity; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_EXECUTION_LOST_ID_ERROR; @@ -20,7 +24,7 @@ import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_EX * @author wangli * @since 2023/10/9 19:30 */ -public class ExpressionConditionCmd implements Command, Serializable { +public class ExpressionConditionCmd extends AbstractCommand implements Serializable { protected final RuntimeService runtimeService; protected final ProcessEngineConfigurationImpl processEngineConfiguration; protected final String processInstanceId; @@ -35,6 +39,14 @@ public class ExpressionConditionCmd implements Command, Serializable { this.exp = exp; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("exp", exp); + return JSON.toJSONString(params); + } + @Override public Boolean execute(CommandContext commandContext) { Expression expression = processEngineConfiguration.getExpressionManager().createExpression(this.exp); diff --git a/workflow-engine-core/src/main/java/org/flowable/engine/impl/cmd/CreateAttachmentCmd.java b/workflow-engine-core/src/main/java/org/flowable/engine/impl/cmd/CreateAttachmentCmd.java index aa30f0396..9f0f63f53 100644 --- a/workflow-engine-core/src/main/java/org/flowable/engine/impl/cmd/CreateAttachmentCmd.java +++ b/workflow-engine-core/src/main/java/org/flowable/engine/impl/cmd/CreateAttachmentCmd.java @@ -1,5 +1,8 @@ package org.flowable.engine.impl.cmd; +import cn.axzo.workflow.core.engine.cmd.AbstractCommand; +import com.alibaba.fastjson.JSON; +import liquibase.pro.packaged.M; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; @@ -22,6 +25,9 @@ import org.flowable.task.api.Task; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import java.io.InputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * 覆盖 Flowable 自带的 CreateAttachmentCmd, 由于 Flowable 5 的实现导致异常,需要覆盖 @@ -29,7 +35,7 @@ import java.io.InputStream; * @author Tom Baeyens * @author Joram Barrez */ -public class CreateAttachmentCmd implements Command { +public class CreateAttachmentCmd extends AbstractCommand implements Serializable { protected String attachmentType; protected String taskId; @@ -50,6 +56,19 @@ public class CreateAttachmentCmd implements Command { this.url = url; } + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("attachmentType", attachmentType); + params.put("taskId", taskId); + params.put("processInstanceId", processInstanceId); + params.put("attachmentName", attachmentName); + params.put("attachmentDescription", attachmentDescription); +// params.put("content", content); + params.put("url", url); + return JSON.toJSONString(params); + } + @Override public Attachment execute(CommandContext commandContext) { diff --git a/workflow-engine-server/pom.xml b/workflow-engine-server/pom.xml index 279ccf123..80e18794a 100644 --- a/workflow-engine-server/pom.xml +++ b/workflow-engine-server/pom.xml @@ -95,10 +95,10 @@ cn.axzo.maokai maokai-api - - cn.axzo.tyr - tyr-api - + + + + cn.axzo.karma karma-api diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java index 1af797b06..ac540b2b4 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java @@ -9,6 +9,7 @@ import org.apache.skywalking.apm.toolkit.trace.TraceContext; import org.slf4j.MDC; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; @@ -18,6 +19,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import static cn.axzo.workflow.common.constant.LogFieldConstants.X_REQUEST_ID; +import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; /** * Http接口日志记录 @@ -44,18 +46,18 @@ public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered } else { MDC.put(X_REQUEST_ID, requestId); } - String ctxLogId = request.getHeader(Constants.CTX_LOG_ID_MDC); + String ctxLogId = request.getHeader(CTX_LOG_ID_MDC); if (Strings.isNullOrEmpty(ctxLogId)) { - MDC.put(Constants.CTX_LOG_ID_MDC, getTraceId()); + MDC.put(CTX_LOG_ID_MDC, getTraceId()); } else { - MDC.put(Constants.CTX_LOG_ID_MDC, ctxLogId); + MDC.put(CTX_LOG_ID_MDC, ctxLogId); } try { filterChain.doFilter(request, response); } finally { - response.setHeader(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC)); - response.setHeader(X_REQUEST_ID, MDC.get(Constants.CTX_LOG_ID_MDC)); + response.setHeader(CTX_LOG_ID_MDC, MDC.get(CTX_LOG_ID_MDC)); + response.setHeader(X_REQUEST_ID, MDC.get(CTX_LOG_ID_MDC)); MDC.clear(); } } @@ -64,4 +66,10 @@ public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered String contextTraceId = TraceContext.traceId(); return Strings.isNullOrEmpty(contextTraceId) ? IdUtil.fastSimpleUUID() : contextTraceId; } + + public static String traceId() { + String xRequestId = MDC.get(X_REQUEST_ID); + return StringUtils.hasText(xRequestId) ? xRequestId : MDC.get(CTX_LOG_ID_MDC); + + } } From 5d330942663a841cbf4adc9e8dc1aa4242c3e171 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 10:49:06 +0800 Subject: [PATCH 204/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/engine/interceptor/CustomRetryInterceptor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java index 62094a5c0..2cfb37dc5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -41,6 +41,7 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { try { // try to execute the command if (AbstractCommand.class.isAssignableFrom(command.getClass())) { + // 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行. log.info("traceId:{} Executing command params: {}", TraceUtil.traceId(), ((AbstractCommand) command).paramToJsonString()); } From 1065db0f6f08e31af0883a83b6a8ab1322a49ad0 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 11:04:54 +0800 Subject: [PATCH 205/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/interceptor/CustomRetryInterceptor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java index 2cfb37dc5..fa286a8c4 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -53,10 +53,11 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { failedAttempts++; } while (failedAttempts <= numOfRetries); - throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries)); } catch (Throwable e) { + log.error("Caught exception: {}", e.getMessage(), e); throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_ERROR, e.getMessage()); } + throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries)); } protected void waitBeforeRetry(long waitTime) { From eb3914a838fecadf0f5464640c00d5754487e213 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 11:05:05 +0800 Subject: [PATCH 206/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/server/common/filter/HttpTraceLogFilter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java index ac540b2b4..d8452d23b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/filter/HttpTraceLogFilter.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.server.common.filter; -import cn.azxo.framework.common.constatns.Constants; import cn.hutool.core.util.IdUtil; import com.google.common.base.Strings; import lombok.extern.slf4j.Slf4j; From f9069f9b1fa6e228fac880b83f3490ff08a88794 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 11:29:12 +0800 Subject: [PATCH 207/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/CustomRetryInterceptor.java | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java index fa286a8c4..093f1d108 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -10,7 +10,6 @@ import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandConfig; import org.flowable.common.engine.impl.interceptor.CommandExecutor; -import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_ASYNC_COMMAND_EXECUTION_ERROR; import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP; /** @@ -28,35 +27,31 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { @Override public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { - try { - long waitTime = waitTimeInMs; - int failedAttempts = 0; - do { - if (failedAttempts > 0) { - log.warn("Waiting for {}ms before retrying the command.", waitTime); - waitBeforeRetry(waitTime); - waitTime *= waitIncreaseFactor; + long waitTime = waitTimeInMs; + int failedAttempts = 0; + do { + if (failedAttempts > 0) { + log.warn("Waiting for {}ms before retrying the command.", waitTime); + waitBeforeRetry(waitTime); + waitTime *= waitIncreaseFactor; + } + + try { + // try to execute the command + if (AbstractCommand.class.isAssignableFrom(command.getClass())) { + // 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行. + log.info("traceId:{} Executing command params: {}", TraceUtil.traceId(), + ((AbstractCommand) command).paramToJsonString()); } + return next.execute(config, command, commandExecutor); - try { - // try to execute the command - if (AbstractCommand.class.isAssignableFrom(command.getClass())) { - // 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行. - log.info("traceId:{} Executing command params: {}", TraceUtil.traceId(), - ((AbstractCommand) command).paramToJsonString()); - } - return next.execute(config, command, commandExecutor); + } catch (PersistenceException e) { + log.warn("Caught persistence exception: {}", e.getMessage(), e); + } - } catch (PersistenceException e) { - log.warn("Caught persistence exception: {}", e.getMessage(), e); - } + failedAttempts++; + } while (failedAttempts <= numOfRetries); - failedAttempts++; - } while (failedAttempts <= numOfRetries); - } catch (Throwable e) { - log.error("Caught exception: {}", e.getMessage(), e); - throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_ERROR, e.getMessage()); - } throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries)); } From 6db32fff3860330349a789a392dff01614457191 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 11:32:40 +0800 Subject: [PATCH 208/210] =?UTF-8?q?update=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E4=BB=BB=E5=8A=A1=E5=90=8C=E6=97=B6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=90=8C=E4=B8=80=E4=B8=AA=E5=AE=9E=E4=BE=8B,?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E4=BA=8B=E5=8A=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/core/common/code/FlowableEngineRespCode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java index c712329cb..e82a9f833 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java @@ -19,7 +19,7 @@ public enum FlowableEngineRespCode implements IModuleRespCode { ENGINE_USER_TASK_PARAM_ERROR("004", "构建后的查询审批人入参为空. 任务节点【nodeId:{}】, 该节点选择的\"审批人所在范围\"是:【{}】,请检查 cooperationOrg 参数"), ENGINE_NOTICE_CUSTOM_FLOW_ELEMENT_ERROR("005", "查询通知目标用户前参数发生异常,未获取到 WorkspaceType"), ENGINE_ASYNC_COMMAND_EXECUTION_ERROR("006", "引擎出现 SQL 相关异常, 异常信息:【{}】"), - ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现 PersistenceException, 将放弃"), + ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现异常, 将放弃"), ; private String code; From 7bb157c0b6d1a60c20b23a45d59192f5b4f55662 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 3 Jul 2024 13:43:56 +0800 Subject: [PATCH 209/210] =?UTF-8?q?remove=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E6=97=A0=E7=94=A8=E7=9A=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/common/hook/NacosShutdownHook.java | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java deleted file mode 100644 index b2eaa31a8..000000000 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/hook/NacosShutdownHook.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.axzo.workflow.server.common.hook; - -import org.springframework.context.SmartLifecycle; - -/** - * TODO - * - * @author wangli - * @since 2024/6/6 14:35 - */ -public class NacosShutdownHook implements SmartLifecycle { - @Override - public void start() { - - } - - @Override - public void stop() { - - } - - @Override - public boolean isRunning() { - return false; - } -} From 8bd022dfab5f81ecc07dbd145029600f72ad862c Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 10 Jul 2024 10:45:53 +0800 Subject: [PATCH 210/210] =?UTF-8?q?REQ-2516-=E4=BF=AE=E5=A4=8D=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E8=AF=B7=E6=B1=82=E8=AE=B0=E5=BD=95=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=86=B2=E7=AA=81=E5=AF=BC=E8=87=B4=E6=8F=92=E5=85=A5=E5=A4=9A?= =?UTF-8?q?=E6=9D=A1=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/RequestHeaderContextInterceptor.java | 6 +++--- .../axzo/workflow/server/common/util/RedisUtils.java | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java index 233b12fc7..cfc316e8e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java @@ -91,9 +91,9 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { String cacheRepeatKey = REPEAT_KEY + applicationName; log.info("repeatApi key: {}", cacheRepeatKey); - String key = RedisUtils.getCacheObject(cacheRepeatKey); - if (Objects.isNull(key)) { - RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofSeconds(5)); + //success为true表示key不存在,执行成功,false表示key存在,执行失败 + Boolean success = RedisUtils.trySetObject(cacheRepeatKey, "", Duration.ofSeconds(5)); + if (success) { KEY_CACHE.set(cacheRepeatKey); insert(extAxProperty, applicationName, clientVersion, manageableStatus); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RedisUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RedisUtils.java index 7ecef815f..fcb207f7a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RedisUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RedisUtils.java @@ -7,6 +7,7 @@ import org.redisson.api.RAtomicLong; import org.redisson.api.RBatch; import org.redisson.api.RBucket; import org.redisson.api.RBucketAsync; +import org.redisson.api.RFuture; import org.redisson.api.RKeys; import org.redisson.api.RList; import org.redisson.api.RMap; @@ -23,6 +24,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -140,6 +142,16 @@ public class RedisUtils { batch.execute(); } + + public static Boolean trySetObject(final String key, final T value, final Duration duration) { + RBatch batch = CLIENT.createBatch(); + RBucketAsync bucket = batch.getBucket(key); + RFuture future = bucket.trySetAsync(value, duration.toMillis(), TimeUnit.MILLISECONDS); + batch.execute(); + return future.join(); + } + + /** * 注册对象监听器 *