You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QuickFixJ对接Bloomberg多IP会话发送消息出现序号过低错误求助

QuickFixJ对接Bloomberg会话序号过低错误解决方案

你遇到的Received logout request: Message with sequence #1 is too low (expected sequence #2)错误,核心原因是QuickFixJ默认的序号重置逻辑没有遵循Bloomberg要求的前置校验流程,导致服务端不承认你的序号重置请求,两端序号不匹配。


1. 临时应急方案(快速恢复业务)

  • 停止运行应用,找到配置中FileStorePath对应的目录target/data/quickfixlogs,删除两个会话对应的.seqnums后缀的序号存储文件
  • 联系Bloomberg技术支持,要求重置你两个会话对应服务端的起始序号为1
  • 重启应用即可正常连接发送消息,该方案适合紧急恢复业务场景

2. 代码适配Bloomberg序号重置流程(永久解决)

你需要修改QuickFixJApplication实现类,补充TestRequest校验、序号重置的完整逻辑,修改后代码如下:

public class QuickFixJApplication implements Application {
    // 存储会话的TestRequest等待状态,key为SessionID,value为发出的TestRequestID
    private final ConcurrentHashMap<SessionID, String> waitingHeartbeatMap = new ConcurrentHashMap<>();

    @Override
    public void onCreate(SessionID sessionID) {
    }

    @Override
    public void onLogon(SessionID sessionID) {
        // 登陆成功后判断是否需要执行序号重置,可自定义触发规则,比如每日固定时间
        if (needResetSeqNum(sessionID)) {
            sendTestRequest(sessionID);
        }
    }

    @Override
    public void onLogout(SessionID sessionID) {
        waitingHeartbeatMap.remove(sessionID);
    }

    @Override
    public void toAdmin(Message message, SessionID sessionID) {
        // 收到心跳响应后,重登陆时自动携带ResetSeqNumFlag标识
        if (message instanceof Logon && waitingHeartbeatMap.get(sessionID) == null) {
            message.setBoolean(ResetSeqNumFlag.FIELD, true);
            message.setInt(MsgSeqNum.FIELD, 1);
        }
    }

    @Override
    public void fromAdmin(Message message, SessionID sessionID) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon {
        // 处理TestRequest对应的心跳响应
        if (message instanceof Heartbeat) {
            String testReqId = message.getString(TestReqID.FIELD);
            if (testReqId != null && testReqId.equals(waitingHeartbeatMap.get(sessionID))) {
                // 确认无序号缺口,触发带重置标识的重登陆
                waitingHeartbeatMap.remove(sessionID);
                Session.lookupSession(sessionID).logon();
            }
        }
        // QuickFixJ默认会自动响应TestRequest返回心跳,无需额外实现
    }

    @Override
    public void toApp(Message message, SessionID sessionID) throws DoNotSend {
        // 序号同步完成前禁止发送业务消息,避免报错
        if (waitingHeartbeatMap.containsKey(sessionID)) {
            throw new DoNotSend("会话序号同步中,暂无法发送消息");
        }
    }

    @Override
    public void fromApp(Message message, SessionID sessionID) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
    }

    // 发送TestRequest校验链路无序号缺口
    private void sendTestRequest(SessionID sessionID) {
        TestRequest testRequest = new TestRequest();
        String reqId = UUID.randomUUID().toString();
        testRequest.set(new TestReqID(reqId));
        waitingHeartbeatMap.put(sessionID, reqId);
        try {
            Session.sendToTarget(testRequest, sessionID);
        } catch (SessionNotFound e) {
            waitingHeartbeatMap.remove(sessionID);
            e.printStackTrace();
        }
    }

    // 自定义序号重置触发规则,示例为每日凌晨0点触发重置
    private boolean needResetSeqNum(SessionID sessionID) {
        return LocalTime.now().getHour() == 0;
    }
}

同时修改配置文件:

  • 将两个session配置中的ResetSeqNumFlag改为N,序号重置逻辑改由代码自主控制
  • 确认两个会话的SessionQualifier配置为完全不同的值,避免QuickFixJ混用两个会话的序号

3. 注意事项

  • 不要在应用运行过程中手动删除.seqnums序号文件,会直接导致本地和服务端序号错乱
  • 如果连续3次重置序号失败,直接断开会话联系Bloomberg技术支持排查,不要反复重试连接,避免IP被服务端限制
  • 24小时运行的会话建议设置每日固定时间执行一次序号重置,和Bloomberg服务端规则对齐

内容的提问来源于stack exchange,提问作者user16806803

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 18:54:01