feat: 切换定时任务至分布式调度底座
- 以执行账本和有界 Worker 承载重负载任务与故障接管 - 接入统一调度 Starter 并增加 MySQL 迁移、指标和回归测试
This commit is contained in:
@@ -2,7 +2,7 @@ package tech.easyflow.ai.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.common.constant.enums.EnumDataStatus;
|
||||
import tech.easyflow.ai.enums.PublishStatus;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
@@ -15,7 +15,7 @@ import java.util.Objects;
|
||||
/**
|
||||
* 工作流使用权限校验服务。
|
||||
*
|
||||
* <p>统一封装工作流存在性、租户、启用状态和资源使用权限校验,供页面能力和后台任务复用。</p>
|
||||
* <p>统一封装工作流存在性、租户、发布快照和资源使用权限校验,供页面能力和后台任务复用。</p>
|
||||
*/
|
||||
@Service
|
||||
public class WorkflowUsageAuthorizationService {
|
||||
@@ -40,20 +40,20 @@ public class WorkflowUsageAuthorizationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前账号可使用的启用工作流。
|
||||
* 获取当前账号可使用的已发布工作流视图。
|
||||
*
|
||||
* @param workflowId 工作流 ID
|
||||
* @param account 使用工作流的账号
|
||||
* @param denyMessage 校验失败提示
|
||||
* @return 可使用的工作流
|
||||
* @throws BusinessException 工作流不存在、未启用、跨租户或无使用权限时抛出
|
||||
* @return 可使用的工作流发布视图
|
||||
* @throws BusinessException 工作流不存在、未发布、缺少发布快照、跨租户或无使用权限时抛出
|
||||
*/
|
||||
public Workflow requireUsableWorkflow(
|
||||
BigInteger workflowId,
|
||||
LoginAccount account,
|
||||
String denyMessage) {
|
||||
String message = denyMessage == null || denyMessage.isBlank()
|
||||
? "工作流不存在、已禁用或无权使用"
|
||||
? "工作流不存在、未发布或无权使用"
|
||||
: denyMessage;
|
||||
if (workflowId == null || account == null || account.getId() == null
|
||||
|| account.getTenantId() == null) {
|
||||
@@ -62,7 +62,9 @@ public class WorkflowUsageAuthorizationService {
|
||||
Workflow workflow = workflowService.getById(workflowId);
|
||||
boolean usable = workflow != null
|
||||
&& Objects.equals(workflow.getTenantId(), account.getTenantId())
|
||||
&& EnumDataStatus.AVAILABLE.getCode().equals(workflow.getStatus())
|
||||
&& PublishStatus.PUBLISHED.getCode().equals(workflow.getPublishStatus())
|
||||
&& workflow.getPublishedSnapshotJson() != null
|
||||
&& !workflow.getPublishedSnapshotJson().isEmpty()
|
||||
&& resourceAccessService.canAccess(
|
||||
account,
|
||||
CategoryResourceType.WORKFLOW,
|
||||
@@ -71,6 +73,10 @@ public class WorkflowUsageAuthorizationService {
|
||||
if (!usable) {
|
||||
throw new BusinessException(403, 403, message);
|
||||
}
|
||||
return workflow;
|
||||
Workflow published = workflowService.toPublishedView(workflow);
|
||||
if (published == null) {
|
||||
throw new BusinessException(403, 403, message);
|
||||
}
|
||||
return published;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package tech.easyflow.ai.service;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.common.constant.enums.EnumDataStatus;
|
||||
import tech.easyflow.ai.enums.PublishStatus;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
@@ -11,6 +11,7 @@ import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -21,14 +22,14 @@ import static org.mockito.Mockito.when;
|
||||
public class WorkflowUsageAuthorizationServiceTest {
|
||||
|
||||
/**
|
||||
* 验证禁用工作流即使资源权限允许也不能被使用。
|
||||
* 验证未发布工作流即使资源权限允许也不能被使用。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectDisabledWorkflow() {
|
||||
public void shouldRejectUnpublishedWorkflow() {
|
||||
BigInteger workflowId = BigInteger.valueOf(101);
|
||||
WorkflowService workflowService = mock(WorkflowService.class);
|
||||
ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
|
||||
Workflow workflow = workflow(workflowId, BigInteger.TEN, EnumDataStatus.UNAVAILABLE.getCode());
|
||||
Workflow workflow = workflow(workflowId, BigInteger.TEN, PublishStatus.DRAFT, Map.of());
|
||||
LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
|
||||
when(workflowService.getById(workflowId)).thenReturn(workflow);
|
||||
when(resourceAccessService.canAccess(
|
||||
@@ -58,7 +59,8 @@ public class WorkflowUsageAuthorizationServiceTest {
|
||||
Workflow workflow = workflow(
|
||||
workflowId,
|
||||
BigInteger.valueOf(20),
|
||||
EnumDataStatus.AVAILABLE.getCode());
|
||||
PublishStatus.PUBLISHED,
|
||||
Map.of("title", "published"));
|
||||
LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
|
||||
when(workflowService.getById(workflowId)).thenReturn(workflow);
|
||||
WorkflowUsageAuthorizationService service =
|
||||
@@ -71,17 +73,50 @@ public class WorkflowUsageAuthorizationServiceTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证启用、同租户且具有使用权限的工作流可以返回。
|
||||
* 验证已发布、同租户且具有使用权限的工作流返回发布视图。
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnUsableWorkflow() {
|
||||
public void shouldReturnPublishedWorkflowView() {
|
||||
BigInteger workflowId = BigInteger.valueOf(103);
|
||||
WorkflowService workflowService = mock(WorkflowService.class);
|
||||
ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
|
||||
Workflow workflow = workflow(
|
||||
workflowId,
|
||||
BigInteger.TEN,
|
||||
EnumDataStatus.AVAILABLE.getCode());
|
||||
PublishStatus.PUBLISHED,
|
||||
Map.of("title", "published"));
|
||||
Workflow published = new Workflow();
|
||||
published.setId(workflowId);
|
||||
published.setTitle("发布版");
|
||||
LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
|
||||
when(workflowService.getById(workflowId)).thenReturn(workflow);
|
||||
when(resourceAccessService.canAccess(
|
||||
account,
|
||||
CategoryResourceType.WORKFLOW,
|
||||
workflow,
|
||||
ResourceAction.USE)).thenReturn(true);
|
||||
when(workflowService.toPublishedView(workflow)).thenReturn(published);
|
||||
WorkflowUsageAuthorizationService service =
|
||||
new WorkflowUsageAuthorizationService(workflowService, resourceAccessService);
|
||||
|
||||
Workflow result = service.requireUsableWorkflow(workflowId, account, "工作流不可用");
|
||||
|
||||
Assert.assertSame(result, published);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证发布状态异常但缺少快照的工作流不可被后台任务使用。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectPublishedWorkflowWithoutSnapshot() {
|
||||
BigInteger workflowId = BigInteger.valueOf(104);
|
||||
WorkflowService workflowService = mock(WorkflowService.class);
|
||||
ResourceAccessService resourceAccessService = mock(ResourceAccessService.class);
|
||||
Workflow workflow = workflow(
|
||||
workflowId,
|
||||
BigInteger.TEN,
|
||||
PublishStatus.PUBLISHED,
|
||||
Map.of());
|
||||
LoginAccount account = account(BigInteger.ONE, BigInteger.TEN);
|
||||
when(workflowService.getById(workflowId)).thenReturn(workflow);
|
||||
when(resourceAccessService.canAccess(
|
||||
@@ -92,9 +127,10 @@ public class WorkflowUsageAuthorizationServiceTest {
|
||||
WorkflowUsageAuthorizationService service =
|
||||
new WorkflowUsageAuthorizationService(workflowService, resourceAccessService);
|
||||
|
||||
Workflow result = service.requireUsableWorkflow(workflowId, account, "工作流不可用");
|
||||
|
||||
Assert.assertSame(result, workflow);
|
||||
Assert.assertThrows(
|
||||
BusinessException.class,
|
||||
() -> service.requireUsableWorkflow(workflowId, account, "工作流不可用")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,14 +138,18 @@ public class WorkflowUsageAuthorizationServiceTest {
|
||||
*
|
||||
* @param id 工作流 ID
|
||||
* @param tenantId 租户 ID
|
||||
* @param status 工作流状态
|
||||
* @param publishStatus 工作流发布状态
|
||||
* @param snapshot 工作流发布快照
|
||||
* @return 工作流
|
||||
*/
|
||||
private Workflow workflow(BigInteger id, BigInteger tenantId, Integer status) {
|
||||
private Workflow workflow(BigInteger id, BigInteger tenantId,
|
||||
PublishStatus publishStatus,
|
||||
Map<String, Object> snapshot) {
|
||||
Workflow workflow = new Workflow();
|
||||
workflow.setId(id);
|
||||
workflow.setTenantId(tenantId);
|
||||
workflow.setStatus(status);
|
||||
workflow.setPublishStatus(publishStatus.getCode());
|
||||
workflow.setPublishedSnapshotJson(snapshot);
|
||||
return workflow;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user