yxh
2 天以前 1f23e7dfc186c65434eda46fd6756d41fd01e867
jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
@@ -22,6 +22,8 @@
import org.apache.cxf.common.util.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.validation.annotation.Validated;
import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO;
@@ -316,9 +318,45 @@
    @Override
    public void startHurryUpOneBed(Long roomId, String bedNo) {
        singleThreadExecutor.execute(() -> {
            queueServiceTxFunctions.hurryupOneBed(roomId, bedNo);
        });
        // 【缺陷修复】必须等事务提交后再跑:见 runAfterCommit 的说明
        runAfterCommit(() -> singleThreadExecutor.execute(() -> {
            try {
                queueServiceTxFunctions.hurryupOneBed(roomId, bedNo);
            } catch (Exception e) {
                // 原实现不捕获:异常只留在工作线程里,日志一条都没有,现场无从排查
                log.error("[hurryupOneBed] 自动补人执行异常. 工位={}/{}(不影响主流程,下一轮会重试)",
                        roomId, bedNo, e);
            }
        }));
    }
    /**
     * 把「触发自动分流」推迟到**事务提交之后**再执行;不在事务里则直接执行。
     *
     * <p>【缺陷修复·现场反馈】运动试验签到后,患者一直停在医生工作台的
     * 「本诊室排队中(未分配工位)」,必须手工点「拉入」才进候诊区。
     *
     * <p>原因:{@link #queue} 是 {@code @Transactional},插入「排队中」行之后**立即**把
     * 分流任务丢给 {@code singleThreadExecutor}。工作线程用的是**另一个数据库连接**,
     * READ COMMITTED 下看不到主事务尚未提交的那一行 ⇒
     * {@code getFirstWaitingByCheckTypes} 返回 null ⇒ 这次分流什么都没做就退出;
     * 事务提交后又没有任何补偿 ⇒ 患者永远留在「排队中」。
     *
     * <p>为什么低频检查项目(运动试验、食道电生理)几乎必然中招、高频的却"看起来正常":
     * 执行器平时空闲,任务能**立刻**执行(必然早于提交);高频项目任务会排队,
     * 轮到时事务往往已经提交,于是侥幸成功。
     */
    private void runAfterCommit(Runnable task) {
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    task.run();
                }
            });
        } else {
            task.run();
        }
    }
    @Override
@@ -329,9 +367,32 @@
    @Override
    public void startHurryUpOneCheckType(Integer checkType) {
        singleThreadExecutor.execute(() -> {
            queueServiceTxFunctions.hurryupOneCheckType(checkType);
        });
        // 【缺陷修复】必须等事务提交后再跑:见 runAfterCommit 的说明
        runAfterCommit(() -> singleThreadExecutor.execute(() -> {
            try {
                queueServiceTxFunctions.hurryupOneCheckType(checkType);
            } catch (Exception e) {
                log.error("[hurryupOneCheckType] 自动分流执行异常. checkType={}(不影响主流程,下一轮会重试)",
                        checkType, e);
            }
        }));
    }
    /**
     * 兜底:对**有医生在座**的工位触发一次自动补人(由 {@code QueueAutoRefillJob} 周期调用)。
     *
     * <p>注意用的是 {@code hurryupAllSeatedBeds} 而不是 {@code hurryupAllBed}:
     * 后者会把患者推进"已开通但没医生"的工位,周期跑会放大该副作用。
     */
    @Override
    public void startHurryUpAll() {
        runAfterCommit(() -> singleThreadExecutor.execute(() -> {
            try {
                queueServiceTxFunctions.hurryupAllSeatedBeds();
            } catch (Exception e) {
                log.error("[hurryupAllSeatedBeds] 周期补人执行异常(下一轮继续)", e);
            }
        }));
    }
    @Override