I use the MassTransit.AspNetCorepackage to integrate masstransit to asp.net core. So I have the following code in my Startup.cs class:
IBusControl CreateBus(IServiceProvider serviceProvider)
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host(Configuration["rabbitMqUrl"], h =>
{
h.Username(Configuration["rabbitMqUsername"]);
h.Password(Configuration["rabbitMqPassword"]);
});
});
}
services.AddMassTransit(CreateBus);
And the issue is that if the rabbit mq is not available my application tries to reconnect to the host. Is there any way to configure number of attempts - let's say stop trying to reconnect after 3 attempts so my application can run?
The bus.StartAsync() method accepts a CancellationToken, which can be used to cancel starting the bus. There is an overload that accepts a TimeSpan which can be used to specify a timeout for the connection.
The hosted service also accepts a cancellationToken, but I'm not sure how ASP.NET Core determines what to pass to it and how to setup a timeout.
Related
We have the following issue:
Preconditions:
Quarkus application received WebSockets connections
Quarkus application is running in a pod (Kubernetes)
The WebSockets connection is going through layers of 2 load balancers (elb, nginx) but we made sure that we increased the idle connection timeout (300s)
Websocket server must wait for connection closes before the shutdown
The client for the server doesn't have a reconnect mechanism
we have a shutdown hook to wait for the WebSockets sessions closes
Scenario when the pod is about to close:
the application received a SIGTERM
Sometimes some connections (but not all) closes with Reason GOING_AWAY (indicates that an endpoint is "going away", such as a server going down or a browser having navigated away from a page)
The shutdown hook:
void onStop(#Observes final ShutdownEvent ev) {
long numActiveSessions = getActiveSessions();
while (numActiveSessions > 0) {
try {
TimeUnit.SECONDS.sleep(waitforfinished);
} catch (InterruptedException e) {
return;
}
numActiveSessions = getActiveSessions();
}
}
There is a better way to do this? Why we received the GOING_AWAY reason? Are quarkus closing the WebSockets when it received a SIGTERM?
Update:
example project: https://github.com/pedrolopix/quarkus-websockets-example
I have an application that connects to a web page that sends and receives text strings over a websocket on port 1234. I do not have access to the front end code, so I cannot change the HTML front end code.
I created an autobahn server with a class derived from WebSocketServer protocol that communicates with the web page over port 1234. This works and I am able to send and receive text to the front end.
However, I need to process incoming data and would like to publish the received data to a crossbar.io container through the router on port 8080 (or any other port). The port to the web browser is fixed at 1234.
It there a way for me to "plug in " the autobahn websocket server into the crossbar router or is there an alternative way to create a websocket server that will allow me to to send and receive the text on port 1234 and at the same time participate in pub/sub and RPC with the crossbar router?
I am assuming you are using Python. If you are not, the answer should still be the same, but depending on the language/library and its implementation the answer can change.
From what you are saying, it does not sound like you really need a "plug in". Crossbar does have these under the description of router components. But unless you really need to attach a Python instance directly to the router either for performance or otherwise, I would recommend keeping your application off the router. It would work perfectly fine as a stand alone instance especially if it is on the same machine where the WAMP router is located where the packets would only require to communicate over loopback (which is VERY fast).
Given that you are using Python:
You can use your WebSocketServer and a WampApplicationServer together. The little hiccup you might run into is starting them up properly. In either scenario Python2.x with twisted or Python3.4 with Asyncio you can only start the reactor/event loop once or an error will ensue. (Both Twisted and Asyncio have the same basic concept) In Asyncio you will get RuntimeError: Event loop is running. if you attempt to start the event loop twice. Twisted has a similar error. Using the ApplicationRunner in twisted, there is an option (second argument in run) not to start up the reactor which you can use after the reactor is already running. In Asyncio, there is no such option, the only way I found out how to do it is to inherit the Application runner and overwrite the run method to start the session to be started as a task. Also, be warned that threads do not cooperate with either event loop unless properly wrapped.
Once you have the two connections set up in one instance you can do whatever you want with the data.
Thanks for the idea, and the problems you mention are exactly what I encountered. I did find a solution however, and thanks to the flexibility of crossbar, created a JavaScript guest that allows me to do exactly what I need. Here is the code:
// crossbar setup
var autobahn = require('autobahn');
var connection = new autobahn.Connection({
url: 'ws://127.0.0.1:8080/ws',
realm: 'realm1'
}
);
// Websocket to Scratch setup
// pull in the required node packages and assign variables for the entities
var WebSocketServer = require('websocket').server;
var http = require('http');
var ipPort = 1234; // ip port number for Scratch to use
// this connection is a crossbar connection
connection.onopen = function (session) {
// create an http server that will be used to contain a WebSocket server
var server = http.createServer(function (request, response) {
// We are not processing any HTTP, so this is an empty function. 'server' is a wrapper for the
// WebSocketServer we are going to create below.
});
// Create an IP listener using the http server
server.listen(ipPort, function () {
console.log('Webserver created and listening on port ' + ipPort);
});
// create the WebSocket Server and associate it with the httpServer
var wsServer = new WebSocketServer({
httpServer: server
});
// WebSocket server has been activated and a 'request' message has been received from client websocket
wsServer.on('request', function (request) {
// accept a connection request from Xi4S
//myconnection is the WS connection to Scratch
myconnection = request.accept(null, request.origin); // The server is now 'online'
// Process Xi4S messages
myconnection.on('message', function (message) {
console.log('message received: ' + message.utf8Data);
session.publish('com.serial.data', [message.utf8Data]);
// Process each message type received
myconnection.on('close', function (myconnection) {
console.log('Client closed connection');
boardReset();
});
});
});
};
connection.open();
I have two WebSocket servers that can communicate wonderfully with a client. They are on two separate machines, implemented in Java and running inside WildFly8 webservers. What I need them to do now is communicate with each other. That means: client sends message to server 1, server 1 sends message to server 2, receives the reply and sends it back to client.
The servers run on different apps in OpenShift and I need them to use websockets. Or some other type of communication, but I haven't managed to find anything that actually works so far (RMI or normal socket connections won't work).
What I basically tried to do is use the same code from the client within the onMessage method of the first server. Something like this:
#OnMessage
public void message(Session session, String msg){
...
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
Session NewSession = container.connectToServer(Client.class, URI.create(URL));
NewSession.getBasicRemote().sendText("Routed :" + input);
...
}
However, the server does not connect to the other server and I don't know why.
Any suggestions?
Thank you!
Put connectToServer inside a try {} catch, you might get an error. Log it.
I'm struggling to do exactly the same things (2 websocket servers, Wildfly 8), and I get a permission denied error. See my post here:
https://stackoverflow.com/questions/30966757/java-server-to-server-communication-with-websockets-permission-denied
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.
I am using activeMQ 5.4 for JMS implementation in my project.
I want to notify user every time application fails to send a message
but I am not getting any handle at occurrence of an exception.
For instance, In case JMS broker is down and I perform a create connection, session etc. or a message send operation within a try block,
control never comes back to catch block or ExceptionListener set for the connection.
My code looks like:
connection = (TopicConnection) (new ActiveMQConnectionFactory(localBrokerURL)).createConnection();
connection.setExceptionListener(new ExceptionListener() {
#Override
public void onException(JMSException arg0) {
System.out.println("Exception Occurred");
}
});
connection.start();
final TopicSession session =conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
final Topic sendTopic = session.createTopic("someTopicName");
where Value of localBrokerURL is
failover://(ssl://localhost:61618?trace=true&wireFormat.maxInactivityDuration=0)
Please help. Any hint is highly appreciated.
that is the intent of the failover: transport. It will hide transport failures and automatically try and reconnect, replaying any jms state when a new connection is established.
There is a transportListener that you can use to get transport suspended and resumed events.
If you remove the failover: component from the broker url, you will get all exceptions propagated up to your client.
just set the timeout property on the connection URI and it will throw an error instead of block the thread...
failover://(ssl://localhost:61618?trace=true&wireFormat.maxInactivityDuration=0)?timeout=10000
see http://activemq.apache.org/failover-transport-reference.html