异步服务的调用处理

工作中,有这样一个需求,A服务需要调用B服务的逻辑来完成后续操作,但是不知道B服务的处理时间。因此A服务设计一个超时时间来请求B服务,在超时时间内没有收到B服务的反馈,就算该请求失败了。

设计逻辑为:A服务设置请求超时时间,在超时时间内,A服务锁定线程,等待B服务反馈,B服务执行完成,通过mq通知A服务,A服务将线程唤醒,接着往下执行

A服务代码如下:

复制代码
	// 用于存储当前任务的等待锁
	private static final HashMap<Long, CountDownLatch> WAIT_LATCH_MAP = new HashMap<>();

	// 用于存储任务执行结果或异常信息 Key: taskId, Value: Exception
	private static final ConcurrentHashMap<Long, Exception> TASK_RESULT_MAP = new ConcurrentHashMap<>();

long taskId = 0;

		try {
			// 2. 触发异步生成任务
			AjaxResult result = SpringUtils.getBean(RemoteCmService.class).generateSyncFile(neMoi);
			taskId = (Long) result.get("data");

			// 1. 创建等待锁
			CountDownLatch latch = new CountDownLatch(1);
			synchronized (WAIT_LATCH_MAP) {
				WAIT_LATCH_MAP.put(taskId, latch);
			}

			// 清理之前的结果记录
			TASK_RESULT_MAP.remove(taskId);

			// 3. 等待 MQ 消息通知 (超时时间设为 2 分钟)
			log.info("Waiting for MQ notification for taskId: {}", taskId);
			boolean completed = latch.await(2, TimeUnit.MINUTES);

			if (!completed) {
				log.error("Timeout waiting for generateSyncFile result for taskId: {}", taskId);
				throw new RelationException("生成配置文件超时:2分钟内未收到MQ完成通知");
			}

			// 4. 检查是否有失败记录
			Exception taskException = TASK_RESULT_MAP.get(taskId);
			if (taskException != null) {
				log.error("Generate sync file failed for taskId: {}", taskId, taskException);
				throw new RelationException("生成配置文件失败: " + taskException.getMessage());
			}

		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
			throw new RelationException("等待生成文件时被中断");
		} finally {
			// 清理锁和结果记录
			synchronized (WAIT_LATCH_MAP) {
				WAIT_LATCH_MAP.remove(taskId);
			}
			TASK_RESULT_MAP.remove(taskId);
		}



	/**
	 * 供 MQ 监听器调用的静态方法,用于释放等待锁并记录结果
	 *
	 * @param taskId  任务ID字符串 (与 createFile 中的 taskKey 对应)
	 * @param neMoi   网元MOI
	 * @param success 是否成功
	 */
	public static void notifyFileGenerationResult(Long taskId, String neMoi, boolean success) {
		CountDownLatch latch;
		synchronized (WAIT_LATCH_MAP) {
			latch = WAIT_LATCH_MAP.get(taskId);
		}

		if (latch != null) {
			if (!success) {
				log.error("Received failure notification for neMoi: {}, taskId: {}", neMoi, taskId);
				// 记录失败异常,供主线程检查
				TASK_RESULT_MAP.put(taskId, new Exception("生成配置文件失败"));
			} else {
				log.info("Received success notification for neMoi: {}, taskId: {}", neMoi, taskId);
			}
			// 释放锁,唤醒主线程
			latch.countDown();
		} else {
			log.warn("No waiting thread found for taskId: {}, neMoi: {}", taskId, neMoi);
		}
	}

B服务代码如下:

复制代码
private void notifyTaskFinish(boolean isSucceed) {
        if (!this.isSonTask) {
            this.syncMgr.finish(this.taskId, isSucceed);
        }
    }


public void finish(long taskId, boolean isSucceed) {
        SyncControllerInfo syncControllerInfo = null;
        if (syncingNeMap != null) {
            syncControllerInfo = syncingNeMap.get(taskId);
            if (syncControllerInfo != null) {
                // syncingNeMap.remove(taskId); // 注意:如果后续还需要查询状态,不要立即移除,或者由消费者确认后移除
                syncControllerInfo.setProgress(100);
                if (isSucceed) {
                    log.info("moi=" + syncControllerInfo.getNeMoi() + ", SyncTask succeed.");
                    syncControllerInfo.setResult(SimplifiedSyncTaskApp.SUCCESS);
                } else {
                    log.error("moi=" + syncControllerInfo.getNeMoi() + ", SyncTask failed.");
                    syncControllerInfo.setResult(SimplifiedSyncTaskApp.FAIL);
                }
            }
        }

        // 发送 MQ 消息通知外部系统(如 VM 模块)
        if (syncControllerInfo != null) {
            sendFinishMqMessage(taskId, isSucceed, syncControllerInfo.getNeMoi());
        } else {
            log.warn("Finish called but no SyncControllerInfo found for taskId: {}", taskId);
            // 即使找不到内存中的对象,也可能需要发送一个基本的完成消息,取决于业务需求
            // sendFinishMqMessage(taskId, isSucceed, null);
        }
    }






   private void sendFinishMqMessage(long taskId, boolean isSucceed, String neMoi) {
        try {
            // 构建消息内容,可以使用 JSON 或自定义对象
            JSONObject jsonObject = new  JSONObject();
            jsonObject.set("taskId", taskId);
            jsonObject.set("success", isSucceed);
            jsonObject.set("neMoi", neMoi);

            String messageBody = jsonObject.toString();
            Destination destination = new ActiveMQTopic(TopicConstant.CM_GENERATE_FILE_RESULT_TOPIC);
            SpringUtils.getBean(JmsMessagingTemplate.class).convertAndSend(destination, messageBody);
            log.info("Sent MQ message for sync task finish. taskId={}, success={}, neMoi={}", taskId, isSucceed, neMoi);
        } catch (Exception e) {
            log.error("Failed to send MQ message for sync task finish. taskId={}", taskId, e);
        }
    }

监听服务如下:

复制代码
@Slf4j
@Component
public class CmGenerateFileResultListener {

    @JmsListener(destination = TopicConstant.CM_GENERATE_FILE_RESULT_TOPIC, containerFactory = "topicListener")
    public void onGenerateFileResult(String message) {
        try {
            log.info("Received CM generate file result: {}", message);
            JSONObject jsonObject = JSONUtil.parseObj(message);

            String neMoi = jsonObject.getStr("neMoi");

            Long taskId = Long.parseLong(jsonObject.getStr("taskId")); //

            boolean isSuccess =  "true".equalsIgnoreCase(jsonObject.getStr("success"));

            // 调用 PreActiveContainPlatCreator 的静态方法通知主线程
            PreActiveContainPlatCreator.notifyFileGenerationResult(taskId ,neMoi, isSuccess);

        } catch (Exception e) {
            log.error("Error processing CM generate file result message: {}", message, e);
        }
    }
}
相关推荐
冻柠檬飞冰走茶6 分钟前
PTA基础编程题目集 7-11 分段计算居民水费(C语言实现)
c语言·开发语言·算法
得物技术6 分钟前
推荐系统体验的数字化突破:得物自动化评测平台的技术实践|AICon 文章整理
算法·架构·llm
VALENIAN瓦伦尼安教学设备23 分钟前
转子/行星/平行轴齿轮箱综合故障模拟实验台可复现常见机械问题
大数据·数据库·人工智能·嵌入式硬件·算法
rannn_11131 分钟前
【力扣hot100】哈希表专题——从两数之和到最长连续序列
java·算法·leetcode·哈希
小保CPP1 小时前
OpenCV C++基于极值区域滤波算法的场景文本检测(OCR)
c++·人工智能·opencv·算法·计算机视觉·ocr
来一碗刘肉面1 小时前
字符串模式匹配(朴素模式匹配算法与KMP算法)
数据结构·算法
dyxal2 小时前
eˣ 的泰勒展开式:从“化繁为简”到“万物统一”的微积分之美
算法
BetterFlow_CFD2 小时前
COMSOL声学仿真基础知识(二)
开发语言·算法·matlab
徐小夕13 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github