RabbitMQ setPort causes ConnectionRefused - spring-boot

I have a simple RabbitMQ example starts as follows :
private Channel channel;
private ConnectionFactory connectionFactory;
#Autowired
public RabbitMqManager() {
connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
//connectionFactory.setPort(15672); // ERROR : this breaks rabbitmq connection
try {
Connection connection = connectionFactory.newConnection();
channel = connection.createChannel();
If I add setPort then it sometimes causes TimeoutException, sometimes ConnectionRefused. I spent half a day to understand what was happening. Then I've commented out the setPort, everything works.
Note : I can see WebUI (http://localhost:15672) without any problem and server is up & running.
Why setPort breaks the connection initialization? Does RabbitMQ search all the ports to check available server? or does it use the default port 15672 ?

The default port is 5672, not 15672. This is why it works when you comment the line, it's setting the correct port as it's taking the default one. You can check this by calling setPort(5672) (although this is not necessary to set the port, but it will show that the issue is the port number and not the fact you're calling this function).

Related

Spring Integration TCP Multiple sockets on client side to one server address

Requisites:
I should open multiple sockets/connections to the same server IP and
Port.
I should detect from which connection a request has come and
reroute the response to the same connection
A connection is represented as server Ip and port + client Ip and
port
Each connection has to be single-use=false, it is expected to have multiple request/replies
I'm using collaborating TcpReceivingChannelAdapter and TcpSendingMessageHandler with TcpNetClientConnectionFactory.
And IntegrationFlow for generating those connections dynamically.
How to create multiple sockets for TcpNetClientConnectionFactory that all point to the same Host and port?
I know how to set destination with new TcpNetClientConnectionFactory(host, port). But I'm unable to see or find how to affect which port is used
Should it be done with multiple TcpNetClientConnectionFactory each being bound to one inbound and outbound TCP adapter?
How can I set the local port for those connections? or at least how to obtain it?
I don't seem to find any documentantion about this option. The most similar would be This question
You need a separate connection factory/adapters for each.
See TCP Connection Events.
Use an ApplicationListener or #EventListener to receive TcpConnectionEvents.
The event has getConnectionId() which contains both the local and remote port; the event also has the connection factory bean name.
Or you can cast getSource() to TcpConnection and call getPort() (but you should not otherwise interact with the TcpConnection object.

.NET Remoting keeps a listening socket if I stop debugging server program

I have sporadic issue, it is not happening always.
I have windows service which listening on some port (.NET Remoting).
Here the code of registering channel:
void RegisterChannel(int portNumber, string bindTo)
{
ListDictionary channelProperties = new ListDictionary();
channelProperties.Add("name", Guid.NewGuid().ToString().ToUpper());
channelProperties.Add("port", portNumber);
channelProperties.Add("bindTo", bindTo);
channelProperties.Add("secure", true.ToString());
channelProperties.Add("impersonate", true.ToString());
channelProperties.Add("useIpAddress", false.ToString());
BinaryClientFormatterSinkProvider clientFormatter = new BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverFormatter = new BinaryServerFormatterSinkProvider();
serverFormatter.TypeFilterLevel = TypeFilterLevel.Full;
TcpChannel tcpChannel = new TcpChannel(channelProperties, clientFormatter, serverFormatter);
ChannelServices.RegisterChannel(tcpChannel, true);
}
RegisterChannel(9000, "[::]");
RegisterChannel(9000, "0.0.0.0");
RemotingConfiguration.RegisterWellKnownServiceType(typeof(AccessServer), "AccessLayer", WellKnownObjectMode.Singleton);
If I start debugging of this service in Visual Studio and then stop debugging, after that I am unable to start debugging.
I am getting following exception:
Only one usage of each socket address (protocol/network address/port) is normally permitted
Running netstat –anbo shows:
TCP 0.0.0.0:9000 0.0.0.0:0 LISTENING 3432 [System]
TCP [::]:9000 [::]:0 LISTENING 3432 [System]
After that I have to reboot, otherwise port is taken forever.
Any ideas how to fix it?
Firstly, is the service process definitely being terminated when you stop debugging? It is possible to start the debugger and then for the process to continue after you detach again - meaning that the service code would still be running and so still be occupying the port.
You also might want to change your service so that you explicitly unregister the channel. I've written Windows Services in the past that use Remoting and in "OnStart" a TcpChannel is configured, just as with the code in your question, then in "OnStop" that channel is unregistered by calling "UnregisterChannel" -
public static void UnregisterChannel(IChannel chan)
{
// Due to some weird behaviour we can only remove the registered channel
// by spinning through the list of channels
foreach (IChannel ch in ChannelServices.RegisteredChannels)
{
if (ch.Equals(chan))
{
ChannelServices.UnregisterChannel(ch);
return;
}
}
}
In order to do this, you'll need to keep a reference to "tcpChannel" hanging around so that you can unregister it when you're finished.
You would think that you could just call "ChannelServices.UnregisterChannel" directly with the tcpChannel reference that you are now keeping hold of until "tidy up time" but I encountered some problems with this - I can't recall precisely what the symptoms were but I remember that they were avoided by looping through the RegisteredChannels set and looking for a reference that claimed to Equals my channel reference and then passing that to "ChannelServices.UnregisterChannel".

Multi Instance MQ set up

I am trying to set up Multi Instance MQ. I have configured NFS and able to see the active and stand by instances using dspmq -x. However my doubt is after this setup how to proceed further.
How can I configure the channel(s). I got CONNAME property should be use for this. e.g. CONNAME(<ip><port>,<ip><port>). I am not aware how to do it exactly.
How many listeners I need to start.
For normal mode of MQ, I follow the below steps:
1. crtmqm QM
2. strmqm QM
3. runmqsc QM
4. runmqlsr -m QM -t tcp -p 1125
5. runmqsc QM
6. define channel(SYSTEM.ADMIN.SVRCONN) chltype(SVRCONN) mcauser('mqm')
For multi-instance MQ, what changes I have to do for the below steps. There are many good documents available for Multi Instance MQ set up, but most of these are limited to how to configure the queue manager with multi-instance. Could anybody please guide me for the remaining steps.
Any guidance is much appreciated.
EDIT
Thanks Shashi and Morag for the guidance.
I have created different listeners on port 1600 in both the servers. I have created the below channel:
DEFINE CHANNEL(MYCHANNEL) CHLTYPE(CLNTCONN) TRPTYPE(TCP)
CONNAME('IP11600),IP2(1600)')
DEFINE CHANNEL(MYCHANNEL) CHLTYPE(SVRCONN) TRPTYPE(TCP) MCAUSER(' ')
Below is the stand alone java code I am using to put a message in queue.
public class MutilInstanceMq
{
public static void main(String[] args)
{
sendMsg("Test Message");
}
public static void sendMsg(String msg)
{
MQQueueConnectionFactory connectionFactory = null;
QueueConnection queueConn = null;
QueueSession queueSession = null;
QueueSender queueSender = null;
TextMessage message = null;
try
{
connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setConnectionNameList("<IP1>(1600), <IP2>(1600)");
connectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
connectionFactory.setQueueManager("MYQM1");
connectionFactory.setChannel("MYCHANNEL");
queueConn = connectionFactory.createQueueConnection(" ","password");
queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queueSession.createQueue("MYQ"));
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
message = queueSession.createTextMessage(msg);
message.setJMSCorrelationID("12345");
queueSender.send(message);
queueConn.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
With the above code I end up with the below exception while creating the connection.
> com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ0018: Failed to
> connect to queue manager 'MYQM1' with connection mode 'Client' and
> host name 'IP1(1600),IP2(1600)'. Check the queue manager is
> started and if running in client mode, check there is a listener
> running. Please see the linked exception for more information.
Detailed Print stack trace is:
com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ0018: Failed to connect to queue manager 'MYQM1' with connection mode 'Client' and host name 'IP1(1600),IP2(1600)'. Check the queue manager is started and if running in client mode, check there is a listener running. Please see the linked exception for more information.
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:608)
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:236)
at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:440)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createV7ProviderConnection(WMQConnectionFactory.java:7062)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:6453)
at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createConnection(JmsConnectionFactoryImpl.java:295)
at com.ibm.mq.jms.MQConnectionFactory.createCommonConnection(MQConnectionFactory.java:6230)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:144)
at MutilInstanceMq.sendMsg(MutilInstanceMq.java:40)
at MutilInstanceMq.main(MutilInstanceMq.java:17)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2543' ('MQRC_STANDBY_Q_MGR').
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:223)
... 8 more
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2543;AMQ9204: Connection to host 'IP2(1600)' rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2543;AMQ9487: Remote queue manager is a standby queue manager instance. [3=MYCHANNEL]],3=IP2(1600),5=RemoteConnection.analyseErrorSegment]
at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:2010)
at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:1227)
at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:355)
... 7 more
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2059;AMQ9204: Connection to host 'IP1(1600)' rejected. [3=IP1(1600)]
at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:1980)
... 9 more
Where I am going wrong? Meanwhile I have turned off channel authentication and able to connect to the queue.
To answer your explicit questions:
If you want to use the comma-separated CONNAME method, then you'll end up with something like this. CONNAME('machine1(1234),machine2(1234)'). You should have the same port number in both.
You have two options here. Either use runmqlsr on each machine - so you have two listeners, on the same port. The purpose of the one on the primary machine is for connections to be able to connect to the queue manager. The purpose of the one on the standby machine is to reject connections which try to connect there more quickly than they could be rejected by TCP working out that there is no listener. It also means that the error reported by the connection for the reason it could not connect is much more explicit - "This machine is the standby" rather than "no TCP listener here".
The alternate option is to define a LISTENER object and have it controlled by the queue manager, this way it will only run where the queue manager runs. This keeps the configuration all within the queue manager, but does mean you don't get the benefits outlined above.
The steps are well documented in Knowledge Center here: http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.1.0/com.ibm.mq.doc/fa70161_.htm?lang=en. How to verify the multi-instance setup is described here: http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.1.0/com.ibm.mq.doc/fa70163_.htm?lang=en.

SFTP connection issue with DefaultSftpSessionFactory

I am trying to connect to one particular SFTP server with org.springframework.integration.sftp.session.DefaultSftpSessionFactory.
Connection is lost right after establishing connection.
Caused by: com.jcraft.jsch.JSchException: failed to send channel request
at com.jcraft.jsch.Request.write(Request.java:65)
at com.jcraft.jsch.RequestSftp.request(RequestSftp.java:47)
at com.jcraft.jsch.ChannelSftp.start(ChannelSftp.java:217)
at com.jcraft.jsch.Channel.connect(Channel.java:208)
at com.jcraft.jsch.Channel.connect(Channel.java:145)
at
With the same library I connect to several different SFTP servers without any issues.
Then I tried to connect from command line with below command but failed.
sftp -oIdentityFile=sftp_user_rsa -oUser=sftp_user sftp.zzzz.com
After trying quite a few times with different parameters I connected after specifying a subsystem.
sftp -oIdentityFile=sftp_user_rsa -oUser=sftp_user
-s/usr/libexec/sftp-server sftp.zzzz.com
Also filezilla connects without any issues.
Under the hood DefaultSftpSessionFactory is using sftp channel and setting subsystem to be sftp.
That part is hard coded.
Is there any way to use a different subsystem with this library?
Many thanks
After extending the library (Spring integration SFTP) and the library it is using (JSch) still not working. Even when changed the RequestSftp from source as follows and replaced the hard coded subsystem;
public class RequestSftp extends Request{
RequestSftp(){
setReply(true);
}
public void request(Session session, Channel channel) throws Exception{
super.request(session, channel);
Buffer buf=new Buffer();
Packet packet=new Packet(buf);
packet.reset();
buf.putByte((byte)Session.SSH_MSG_CHANNEL_REQUEST);
buf.putInt(channel.getRecipient());
buf.putString(Util.str2byte("subsystem"));
buf.putByte((byte)(waitForReply() ? 1 : 0));
buf.putString(Util.str2byte("the-new-subsystem"));
write(packet);
}
}
Please open an 'Improvement' JIRA Issue. Currently, you will have to subclass (or clone) the DefaultSftpSessionFactory and DefaultSftpSession, overriding the getSession() method in the factory. Unfortunately, connect() in the session is package-private so you can't simply override that.
It looks like you would just have to change these two lines
SftpSession sftpSession = new SftpSession(jschSession);
sftpSession.connect();
MySftpSession sftpSession = new MySftpSession(jschSession);
sftpSession.connect(subsystem);
Where subsystem would be a property on MySftpSessionFactory and connect(String subsystem) would be similar to connect() on SftpSession.
However, I notice that getSession() uses some other private methods (such as initJschSession) so it might be easier to just copy the factory and give it a new name. I hate to suggest that, but it's not very friendly for subclassing right now. Please make a note of it in the JIRA issue (in addition to adding the subsystem, we should make the factory easier to subclass.

Reconnecting with MQ - issues

I'm looking forward to implement a somewhat intelligent MQ comms module, which should be tolerant for the outages in the network connection. Basically it should try to reconnect each 5 seconds if connection was lost.
The problem is the following. I use the following code for reading:
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueGetMessageOptions = new MQGetMessageOptions();
queueGetMessageOptions.Options = MQC.MQGMO_SYNCPOINT + MQC.MQGMO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING;
queueGetMessageOptions.WaitInterval = 50;
producerQueue.Get(queueMessage, queueGetMessageOptions);
msg = queueMessage.ReadBytes(queueMessage.MessageLength);
(Of course I successfully connect to the queuemanager before etc.)
I got the following issue: when this routine runs, but at the time of .Get there's no connection, the code simply hangs and stays in the .Get.
I use a timer to see if there's a timeout (in theory even that shouldn't be necessary, is that right?) and at the timeout I try to reconnect. BUT when this timeout expires, I still see that the queuemanager reports that it's connected, while its clearly not (no physical connection is present anymore). This issue has popped up since I use SYNCPOINT, and I experience the same when I cut connection during writing, or in this case I try to force a Disconnect on the queuemanager. So please help, what settings shall I use to avoid getting stuck in Get and Put and rather have an MQException thrown or something controllable?
Thanks!
UPDATE: I used the following code to connect to the QueueManager.
Hashtable props = new Hashtable();
props.Add(MQC.HOST_NAME_PROPERTY, Host);
props.Add(MQC.PORT_PROPERTY, Port);
props.Add(MQC.CHANNEL_PROPERTY, ChannelInfo);
if(User!="") props.Add(MQC.USER_ID_PROPERTY, User);
if(Password!="") props.Add(MQC.PASSWORD_PROPERTY, Password);
props.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
queueManager = new MQQueueManager(QueueManagerName, props);
producerQueue = queueManager.AccessQueue(
ProducerQueueName,
MQC.MQOO_INPUT_AS_Q_DEF // open queue for input
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
consumerQueue = queueManager.AccessQueue(
ConsumerQueueName,
MQC.MQOO_OUTPUT + MQC.MQOO_BROWSE + MQC.MQOO_INPUT_AS_Q_DEF // open queue for output
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
Needless to say that normally the code works well. Read/Write, connect/disconnect works as it should, I only have to figure out the current issue.
Thanks!
What version of MQ are you using? For automatic reconnection to work the queue manager need to be at least at MQ v701 and MQ .NET client needs to be a MQ v7.1 level.
Assuming you are using MQ v7.1 .NET client, you need to specify reconnect option during connection create. You will need to enable reconnection by adding something like:
props.Add(MQC.CONNECT_OPTIONS_PROPERTY, MQC.MQCNO_RECONNECT);
Reconnection can be enabled/disabled from mqclient.ini file also.
But what is surprising is why the Get/Put are hanging when there is no network connection. Hope you are not connecting a queue manager running on the same machine as your application. There is no need to set any timer or something like that. You can issue MQ calls and if there is anything wrong with connection, an exception will be thrown.
Update:
I think you are referring to IsConnected property of MQQueueManager class. The documentation says the value of this property: "If true, a connection to the queue manager has been made, and is not known to be broken. Any calls to IsConnected do not actively attempt to reach the queue manager, so it is possible that physical connectivity can break, but IsConnected can still return true. The IsConnected state is only updated when activity, for example, putting a message, getting a message, is performed on the queue manager.
If false, a connection to the queue manager has not been made, or has been broken, or has been disconnected."
As you can see a True value does not mean the connection is still ON. My suggestion would be to call a method, Put/Get and handle any exception thrown.
Put/Get/Disconnect calls hanging appears to be a problem. My suggestion would be raise a PMR with IBM.

Resources