fix(dms): 修复工作流推进时的租户 ID 丢失问题

- 在主线程和异步线程中设置租户上下文
- 通过 Dubbo隐式参数传递租户 ID
- 确保在工作流操作前有正确的租户上下文
- 清理线程本地变量,避免状态污染
master
zch 7 days ago
parent 0f658f33dd
commit b49d7d1e55

@ -13,6 +13,7 @@ import org.apache.dubbo.rpc.RpcContext;
import org.dromara.common.core.constant.DmsConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.dms.api.RemoteInspectInstanceService;
import org.dromara.dms.domain.*;
import org.dromara.dms.mapper.*;
@ -51,6 +52,9 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
// 【重要】在主线程中先登录,确保后续所有调用都有认证上下文
StpUtil.login(userId, "login");
// 【关键修复】设置租户上下文确保工作流能获取到正确的租户ID
TenantHelper.setDynamic(tenantId);
try {
// 创建检查实例
R<Long> rInspectInstanceId = createInspectInstance(planInspectCode, tenantId, userId);
@ -64,6 +68,10 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
RemoteStartProcess remoteStartProcess = new RemoteStartProcess();
remoteStartProcess.setBusinessId(businessId);
remoteStartProcess.setFlowCode(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_WF_CODE);
// 【重要】通过Dubbo隐式参数传递租户ID
RpcContext.getContext().setAttachment("tenantId", tenantId);
RemoteStartProcessReturn result = remoteWorkflowService.startWorkFlow(remoteStartProcess);
if (ObjectUtils.isEmpty(result)) {
@ -76,6 +84,11 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
// 【关键】在异步线程中重新登录相同用户
StpUtil.login(userId, "login");
// 【关键修复】在异步线程中重新设置租户上下文
TenantHelper.setDynamic(tenantId);
log.info("检查工单异步线程中当前租户ID: {}", TenantHelper.getTenantId());
// 【执行业务】更新检查工单的工作流信息
updateInspectWorkflow(inspectInstanceId, taskId);
@ -83,12 +96,17 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
} catch (Exception e) {
log.error("检查工单 {} 异步工作流处理失败: {}", inspectInstanceId, e.getMessage(), e);
} finally {
// 【清理】清理登录状态,避免线程池复用时的状态污染
// 【清理】清理登录状态和租户上下文,避免线程池复用时的状态污染
try {
StpUtil.logout();
} catch (Exception ignored) {
// 忽略登出时的异常
}
try {
TenantHelper.clearDynamic();
} catch (Exception ignored) {
// 忽略清理时的异常
}
// 清理RpcContext
try {
RpcContext.removeContext();
@ -101,12 +119,17 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
}
}
} finally {
// 【主线程清理】确保主线程执行完成后清理登录状态
// 【主线程清理】确保主线程执行完成后清理登录状态和租户上下文
try {
StpUtil.logout();
} catch (Exception ignored) {
// 忽略登出异常
}
try {
TenantHelper.clearDynamic();
} catch (Exception ignored) {
// 忽略清理异常
}
}
}
@ -185,12 +208,24 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
private void updateInspectWorkflow(Long businessId, Long taskId) {
try {
// 【关键修复】确保在工作流操作前有正确的租户上下文
String currentTenantId = TenantHelper.getTenantId();
log.info("检查工作流更新前当前租户ID: {}", currentTenantId);
// 1. 更新工作流ID
DmsBillsInspectInstance inspectInstance = dmsBillsInspectInstanceMapper.selectById(businessId);
if (inspectInstance != null) {
inspectInstance.setWfDefinitionId(taskId);
dmsBillsInspectInstanceMapper.updateById(inspectInstance);
int updateResult = dmsBillsInspectInstanceMapper.updateById(inspectInstance);
if (updateResult > 0) {
log.info("检查工单 {} 工作流ID更新成功: {}", businessId, taskId);
} else {
log.error("检查工单 {} 工作流ID更新失败", businessId);
return;
}
} else {
log.error("检查工单 {} 不存在无法更新工作流ID", businessId);
return;
}
// 2. 推进工作流状态
@ -202,9 +237,19 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
messageTypes.add("system"); // 系统消息
completeTask.setMessageType(messageTypes);
// 【关键修复】在调用工作流推进前再次确认租户上下文
log.info("检查工作流推进前当前租户ID: {}", TenantHelper.getTenantId());
// 【重要】通过Dubbo隐式参数传递租户ID
RpcContext.getContext().setAttachment("tenantId", currentTenantId);
// 【关键】调用工作流推进
remoteWorkflowService.completeTask(completeTask);
boolean completeResult = remoteWorkflowService.completeTask(completeTask);
if (completeResult) {
log.info("检查工单 {} 工作流推进成功", businessId);
} else {
log.warn("检查工单 {} 工作流推进失败,但工单已创建成功", businessId);
}
} catch (Exception e) {
log.error("检查工单 {} 工作流更新失败: {}", businessId, e.getMessage(), e);

@ -15,6 +15,7 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.uuid.Seq;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.dms.domain.*;
import org.dromara.dms.domain.bo.*;
import org.dromara.dms.domain.vo.*;
@ -69,6 +70,9 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
// 【重要】在主线程中先登录,确保后续所有调用都有认证上下文
StpUtil.login(userId, "login");
// 【关键修复】设置租户上下文确保工作流能获取到正确的租户ID
TenantHelper.setDynamic(tenantId);
try {
R<Long> RLubeStanceId = LubeStance(planLubeCode, tenantId, userId);
Long LubeStanceId = RLubeStanceId.getData();
@ -79,6 +83,10 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
RemoteStartProcess remoteStartProcess = new RemoteStartProcess();
remoteStartProcess.setBusinessId(businessId);
remoteStartProcess.setFlowCode(DmsConstants.DMS_BILLS_LUBE_INSTANCE_WF_CODE);
// 【重要】通过Dubbo隐式参数传递租户ID
RpcContext.getContext().setAttachment("tenantId", tenantId);
RemoteStartProcessReturn result = remoteWorkflowService.startWorkFlow(remoteStartProcess);
//TODO:赋值给工单的wfid
if(ObjectUtils.isEmpty(result)){
@ -92,6 +100,11 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
// 这样可以确保生成有效的Token并自动设置到Sa-Token上下文中
StpUtil.login(userId, "login");
// 【关键修复】在异步线程中重新设置租户上下文
TenantHelper.setDynamic(tenantId);
log.info("异步线程中当前租户ID: {}", TenantHelper.getTenantId());
// 【执行业务】更新润滑工单的工作流信息
updateWarmFlow(LubeStanceId, taskId);
@ -99,12 +112,17 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
} catch (Exception e) {
log.error("润滑工单 {} 异步工作流处理失败: {}", LubeStanceId, e.getMessage(), e);
} finally {
// 【清理】清理登录状态,避免线程池复用时的状态污染
// 【清理】清理登录状态和租户上下文,避免线程池复用时的状态污染
try {
StpUtil.logout();
} catch (Exception ignored) {
// 忽略登出时的异常
}
try {
TenantHelper.clearDynamic();
} catch (Exception ignored) {
// 忽略清理时的异常
}
// 清理RpcContext
try {
RpcContext.removeContext();
@ -117,13 +135,18 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
}
}
} finally {
// 【主线程清理】确保主线程执行完成后清理登录状态
// 【主线程清理】确保主线程执行完成后清理登录状态和租户上下文
// 注意这里不影响异步线程因为每个线程都有自己的ThreadLocal
try {
StpUtil.logout();
} catch (Exception ignored) {
// 忽略登出异常
}
try {
TenantHelper.clearDynamic();
} catch (Exception ignored) {
// 忽略清理异常
}
}
}
@ -203,12 +226,26 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
private void updateWarmFlow(Long businessId,Long taskId){
try {
// 【关键修复】确保在工作流操作前有正确的租户上下文
String currentTenantId = TenantHelper.getTenantId();
log.info("工作流更新前当前租户ID: {}", currentTenantId);
// 1. 更新工作流ID
DmsBillsLubeInstanceVo dmsBillsLubeInstanceVo = dmsBillsLubeInstanceService.queryById(businessId);
if (dmsBillsLubeInstanceVo == null) {
log.error("润滑工单 {} 不存在无法更新工作流ID", businessId);
return;
}
DmsBillsLubeInstance billsLubeInstance = MapstructUtils.convert(dmsBillsLubeInstanceVo, DmsBillsLubeInstance.class);
billsLubeInstance.setWfDefinitionId(taskId);
dmsBillsLubeInstanceMapper.updateById(billsLubeInstance);
int updateResult = dmsBillsLubeInstanceMapper.updateById(billsLubeInstance);
if (updateResult > 0) {
log.info("润滑工单 {} 工作流ID更新成功: {}", businessId, taskId);
} else {
log.error("润滑工单 {} 工作流ID更新失败", businessId);
return;
}
// 2. 推进工作流状态
RemoteCompleteTask completeTask = new RemoteCompleteTask();
@ -219,9 +256,19 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
messageTypes.add("system"); // 系统消息
completeTask.setMessageType(messageTypes);
// 【关键修复】在调用工作流推进前再次确认租户上下文
log.info("工作流推进前当前租户ID: {}", TenantHelper.getTenantId());
// 【重要】通过Dubbo隐式参数传递租户ID
RpcContext.getContext().setAttachment("tenantId", currentTenantId);
// 【关键】调用工作流推进可能会因为Token问题失败
remoteWorkflowService.completeTask(completeTask);
boolean completeResult = remoteWorkflowService.completeTask(completeTask);
if (completeResult) {
log.info("润滑工单 {} 工作流推进成功", businessId);
} else {
log.warn("润滑工单 {} 工作流推进失败,但工单已创建成功", businessId);
}
} catch (Exception e) {
log.error("润滑工单 {} 工作流更新失败: {}", businessId, e.getMessage(), e);

@ -13,6 +13,7 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.uuid.Seq;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.dms.api.RemoteMaintInstanceService;
import org.dromara.dms.domain.*;
import org.dromara.dms.mapper.DmsBillsMaintDetailMapper;
@ -61,6 +62,9 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
// 【重要】在主线程中先登录,确保后续所有调用都有认证上下文
StpUtil.login(userId, "login");
// 【关键修复】设置租户上下文确保工作流能获取到正确的租户ID
TenantHelper.setDynamic(tenantId);
try {
// 创建保养实例
R<Long> rMaintInstanceId = createMaintInstance(planMaintCode, tenantId, userId);
@ -74,6 +78,13 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
RemoteStartProcess remoteStartProcess = new RemoteStartProcess();
remoteStartProcess.setBusinessId(businessId);
remoteStartProcess.setFlowCode(DmsConstants.DMS_BILLS_MAINT_INSTANCE_WF_CODE);
// 【关键修复】在启动工作流前确保租户上下文存在
log.info("启动保养工作流前当前租户ID: {}", TenantHelper.getTenantId());
// 【重要】通过Dubbo隐式参数传递租户ID
RpcContext.getContext().setAttachment("tenantId", tenantId);
RemoteStartProcessReturn result = remoteWorkflowService.startWorkFlow(remoteStartProcess);
if (ObjectUtils.isEmpty(result)) {
@ -86,6 +97,11 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
// 【关键】在异步线程中重新登录相同用户
StpUtil.login(userId, "login");
// 【关键修复】在异步线程中重新设置租户上下文
TenantHelper.setDynamic(tenantId);
log.info("保养工单异步线程中当前租户ID: {}", TenantHelper.getTenantId());
// 【执行业务】更新保养工单的工作流信息
updateMaintWorkflow(maintInstanceId, taskId);
@ -93,12 +109,17 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
} catch (Exception e) {
log.error("保养工单 {} 异步工作流处理失败: {}", maintInstanceId, e.getMessage(), e);
} finally {
// 【清理】清理登录状态,避免线程池复用时的状态污染
// 【清理】清理登录状态和租户上下文,避免线程池复用时的状态污染
try {
StpUtil.logout();
} catch (Exception ignored) {
// 忽略登出时的异常
}
try {
TenantHelper.clearDynamic();
} catch (Exception ignored) {
// 忽略清理时的异常
}
// 清理RpcContext
try {
RpcContext.removeContext();
@ -111,12 +132,17 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
}
}
} finally {
// 【主线程清理】确保主线程执行完成后清理登录状态
// 【主线程清理】确保主线程执行完成后清理登录状态和租户上下文
try {
StpUtil.logout();
} catch (Exception ignored) {
// 忽略登出异常
}
try {
TenantHelper.clearDynamic();
} catch (Exception ignored) {
// 忽略清理异常
}
}
}
@ -193,12 +219,24 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
private void updateMaintWorkflow(Long businessId, Long taskId) {
try {
// 【关键修复】确保在工作流操作前有正确的租户上下文
String currentTenantId = TenantHelper.getTenantId();
log.info("保养工作流更新前当前租户ID: {}", currentTenantId);
// 1. 更新工作流ID
DmsBillsMaintInstance maintInstance = dmsBillsMaintInstanceMapper.selectById(businessId);
if (maintInstance != null) {
maintInstance.setWfDefinitionId(taskId);
dmsBillsMaintInstanceMapper.updateById(maintInstance);
int updateResult = dmsBillsMaintInstanceMapper.updateById(maintInstance);
if (updateResult > 0) {
log.info("保养工单 {} 工作流ID更新成功: {}", businessId, taskId);
} else {
log.error("保养工单 {} 工作流ID更新失败", businessId);
return;
}
} else {
log.error("保养工单 {} 不存在无法更新工作流ID", businessId);
return;
}
// 2. 推进工作流状态
@ -210,9 +248,19 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
messageTypes.add("system"); // 系统消息
completeTask.setMessageType(messageTypes);
// 【关键修复】在调用工作流推进前再次确认租户上下文
log.info("保养工作流推进前当前租户ID: {}", TenantHelper.getTenantId());
// 【重要】通过Dubbo隐式参数传递租户ID
RpcContext.getContext().setAttachment("tenantId", currentTenantId);
// 【关键】调用工作流推进
remoteWorkflowService.completeTask(completeTask);
boolean completeResult = remoteWorkflowService.completeTask(completeTask);
if (completeResult) {
log.info("保养工单 {} 工作流推进成功", businessId);
} else {
log.warn("保养工单 {} 工作流推进失败,但工单已创建成功", businessId);
}
} catch (Exception e) {
log.error("保养工单 {} 工作流更新失败: {}", businessId, e.getMessage(), e);

Loading…
Cancel
Save