【问题标题】:How do I resolve - MQJE001: An MQException occurred: Completion Code 2, Reason 2009如何解决 - MQJE001:发生 MQException:完成代码 2,原因 2009
【发布时间】:2021-05-06 11:56:39
【问题描述】:

连接到 MQQueueManager 时出现异常。异常读取 - MQException:MQJE001:发生 MQException:完成代码 2,原因 2009 MQJE016:MQ 队列管理器在连接期间立即关闭通道 关闭原因 = 2009。下面是我将消息推送到队列的代码。

@SuppressWarnings("unchecked")
public boolean postMessage(String mqMessage, String correlationId) throws TradeException, MQException {
    String logStr = TradeUtil.getLoggerPrefix(this.getClass().getSimpleName(),
            Thread.currentThread().getStackTrace()[1].getMethodName(), "");
    boolean result = false;

    MQQueueManager queueManager = null;

    try {
        
        MQEnvironment.hostname = ConfigFileLoader.getProperty("MQ_HOSTNAME");
        MQEnvironment.channel = ConfigFileLoader.getProperty("MQ_CHANNEL");
        MQEnvironment.port = Integer.parseInt(ConfigFileLoader.getProperty("MQ_PORT"));

        tradeLogger.info(logStr + "MQ HOST NAME : " + MQEnvironment.hostname + " MQ CHANNEL : "
                + MQEnvironment.channel + " MQ PORT : " + MQEnvironment.port);
        try {
            queueManager = new MQQueueManager(ConfigFileLoader.getProperty("MQ_QUEUE_MANAGER"));
        } catch (MQException e) {
            tradeLogger.info("queueManager is Busy, try after some time");
            Thread.sleep(1000 * 60);
            if(maxCount < 3) {
                maxCount += 1;
                postMessage(mqMessage, correlationId);  
            }
        }
        
        tradeLogger.info(logStr + "MQhostname : " + queueManager + ConfigFileLoader.getProperty("MQ_QUEUE_MANAGER"));

        int openOptions = MQC.MQOO_OUTPUT + MQC.MQOO_INPUT_AS_Q_DEF;
        MQQueue queue = queueManager.accessQueue(ConfigFileLoader.getProperty("MQ_INPUT_QUEUE_NAME"), openOptions);
        tradeLogger.info("INPUT QUEUE NAME : " + queue + ConfigFileLoader.getProperty("MQ_INPUT_QUEUE_NAME"));

        if (queueManager.isConnected()) {
            tradeLogger.info("queue manager is connected!");
            MQPutMessageOptions mqPutMessageOptions = new MQPutMessageOptions();
            MQMessage message = new MQMessage();
            message.format = MQC.MQFMT_STRING;
            message.correlationId = correlationId.getBytes();
            message.writeString(mqMessage);
            queue.put(message, mqPutMessageOptions);

            tradeLogger.info(logStr + "POSTED MESSAGE : " + mqMessage);
            result = true;

            queue.close();

            tradeLogger.info("queue is closed.");

        } else {
            tradeLogger.error("unable to connect to Queue");
            throw new TradeException("Unable to connect to Queue");
        }

    } catch (MQException e) {
        tradeLogger.error(logStr + " MQException : " + e.getMessage());
        JSONObject errorJSON = new JSONObject();
        errorJSON.put("errorDesc", e);
        throw new TradeException(ResponseStatus.failure, 404,
                "Unable to post message in MQ. Please try after sometime.", errorJSON);
    } catch (Exception e) {
        tradeLogger.error(logStr + " Exception : " + e.getMessage());
        JSONObject errorJSON = new JSONObject();
        errorJSON.put("errorDesc", e);
        throw new TradeException(ResponseStatus.failure, 404,
                "Unable to post message in MQ due to some techical error. Please contact administrator.",
                errorJSON);
    } finally {
        if (null != queueManager) {
            queueManager.disconnect();
            tradeLogger.info("queueManager is disconnected!");
        }
    }
    return result;
}

此问题在手动重新启动队列管理器后得到解决。另外,我在某处读到 MQQueueManager() 是同步的。是否有其他线程可能正在访问此队列管理器以建立导致此异常的连接?

【问题讨论】:

  • MQQueueManager() 创建到队列管理器的连接,是的,它是同步调用。您是否需要在每次要放置消息时都连接到队列管理器?除非您不经常发送//获取消息,否则这不是一个好习惯。一个很好的做法是创建一次连接并在每次放置/获取消息时使用它,并在完成放置/获取后关闭连接
  • @Shashi - 是的,需要从源和目标队列中放置/获取消息。那里有一个调度程序,它将每 2 分钟创建一个新连接以检查队列深度 > 0 以提取消息。
  • 感谢@Shashi - 正确处理关闭 MQ 管理器后,问题得到解决。从目标队列拉取消息后,我没有关闭队列管理器。

标签: ibm-mq message-queue mq


【解决方案1】:

这不是你得到的 2009 年的答案。我有你的代码的简化版本

@SuppressWarnings("unchecked")
public boolean postMessage(String mqMessage, String correlationId) throws MQException {
    boolean result = false;

    MQQueueManager queueManager = null;
    MQQueue queue = null;
    MQEnvironment.hostname = "localhost";
    MQEnvironment.channel = "SVRCONN_CHN";
    MQEnvironment.port = 1414;

    try {
        queueManager = new MQQueueManager("QM1");
        int openOptions = MQC.MQOO_OUTPUT; // Just open for putting message
        queue = queueManager.accessQueue("DESTQ", openOptions);
        MQPutMessageOptions mqPutMessageOptions = new MQPutMessageOptions();
        MQMessage message = new MQMessage();
        message.format = MQC.MQFMT_STRING;
        message.correlationId = correlationId.getBytes();
        message.writeString(mqMessage);
        queue.put(message, mqPutMessageOptions);
        result = true;
    } catch (MQException e) {
        e.printStackTrace();                
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        if (queue != null)
            queue.close();

        if (queueManager != null)
            queueManager.disconnect(); // Call disconnect
    }
    return result;
}

【讨论】:

    【解决方案2】:

    首先,不要使用 MQEnvironment 类,因为它不是线程安全的。我希望 IBM 会弃用该类。您应该将您的连接信息放在一个 Hashtable 中,并将 Hashtable 传递给 MQQueueManager 对象。

    Java 示例:

    Hashtable<String, Object> mqht = new Hashtable<String, Object>();
    
    mqht.put(CMQC.CHANNEL_PROPERTY, ConfigFileLoader.getProperty("MQ_CHANNEL"));
    mqht.put(CMQC.HOST_NAME_PROPERTY, ConfigFileLoader.getProperty("MQ_HOSTNAME"));
    mqht.put(CMQC.PORT_PROPERTY, Integer.parseInt(ConfigFileLoader.getProperty("MQ_PORT"));
    mqht.put(CMQC.USER_ID_PROPERTY, ConfigFileLoader.getProperty("MQ_USERID")));
    mqht.put(CMQC.PASSWORD_PROPERTY, ConfigFileLoader.getProperty("MQ_PASSWORD")));
    
    queueManager = new MQQueueManager(ConfigFileLoader.getProperty("MQ_QUEUE_MANAGER"), mqht);
    

    C# .NET 示例:

    Hashtable mqht = new Hashtable();
    
    mqht.Add(MQC.CHANNEL_PROPERTY, ConfigFileLoader.getProperty("MQ_CHANNEL"));
    mqht.Add(MQC.HOST_NAME_PROPERTY, ConfigFileLoader.getProperty("MQ_HOSTNAME"));
    mqht.Add(MQC.PORT_PROPERTY, System.Int32.Parse(ConfigFileLoader.getProperty("MQ_PORT"));
    mqht.Add(MQC.USER_ID_PROPERTY, ConfigFileLoader.getProperty("MQ_USERID")));
    mqht.Add(MQC.PASSWORD_PROPERTY, ConfigFileLoader.getProperty("MQ_PASSWORD")));
    
    mqht.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
    
    queueManager = new MQQueueManager(ConfigFileLoader.getProperty("MQ_QUEUE_MANAGER"), mqht);
    

    此外,为了获得适当的安全性,您应该为与队列管理器的连接设置用户 ID 和密码。

    最后,请确保按照 Shashi 在其代码示例中的说明关闭所有打开的队列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-08
      • 2014-03-07
      • 1970-01-01
      • 1970-01-01
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多