I'm implement websocket in spring-boot 1.5.8, on my local it working fine, but when I deploy to server (run in embedded server) the message notify from server is not stable, sometime client can receive message sometime not.
I check on the log and I got a message
2019-03-20 08:04:08.723 INFO 15506 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats : WebSocketSession[2 current WS(2)-HttpStream(0)-HttpPoll(0), 167 total, 0 closed abnormally (0 connect failure, 0 send limit, 27 transport error)], stompSubProtocol[processed CONNECT(107)-CONNECTED(107)-DISCONNECT(2)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1149], outboundChannelpool size = 0, active threads = 0, queued tasks = 0, completed tasks = 306], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 4, completed tasks = 4468]
(0 connect failure, 0 send limit, 27 transport error)
The log message show that 27 message error, I don't know how to resolve that.
Can we handle on error message event to resolve this problem?
UPDATE
My websocket server
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/queue");
registry.enableSimpleBroker("/notify", "/queue", "/user");
registry.setUserDestinationPrefix("/user");
}
On client side
function connect() {
var socket = new SockJS('http://localhost:8080/ws/');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
stompClient.subscribe('/user/queue/notify', function(notification) {
notify(notification.body)
});
});
return;
}
/**
* Display the notification message.
*/
function notify(message) {
$("#notifications-area").append(message + "\n");
return;
}
Related
I am implementing an JMS MDB solution for invoking webservices that would be triggered from several points in the application. For the sake of validating my solution I am just passing Integer objects right now. I am forcing the code to redeliver messages when the Integer is greater than 5. However, if the message has been redelivered twice it should be ignored/commit. The wait time configured in Websphere is 5 mins, and the max failed deliveries per message is 0 (under Exception destination on Buses -> {bus} -> Destinations -> {destination}).
The problem is when message for object 6 is sent back to queue for re-delivery after 5 mins, the messages for 7, 8, 9... are also put on hold until 6 is redelivered. Although I know JMS does not guarantees message delivery order, but usually it is FIFO. But once a message has been sent back to the queue and redelivered, the order of remaining messages is not sequential. i.e. it is something like 6, 8, 9, 7.
Under JMS Activation specifications Maximum batch size is 1 and Maximum concurrent MDB invocations per endpoint is 10.
Any idea how to deal with new messages that are blocked due to message on hold? I referred the question at this link, it says that the queue should not be blocked.
JMS and MDB with setRollbackOnly
Also please provide suggestions on maintaining message order.
Snippet of code:
public void onMessage(javax.jms.Message msg) {
try {
if (msg instanceof ObjectMessage) {
ObjectMessage objMsg = (ObjectMessage)msg;
Object obj = objMsg.getObject();
UserTransaction userTxn = getMessageDrivenContext().getUserTransaction();
userTxn.begin();
InitialContext initialContext = new InitialContext();
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/cf");
javax.jms.Connection conn = cf.createConnection();
Session jmsSession = conn.createSession(true, -1);
Queue queue = (Queue) initialContext.lookup("jms/queue1");
QueueBrowser queueBrowser = jmsSession.createBrowser(queue);
Enumeration enumeration = queueBrowser.getEnumeration();
while (enumeration.hasMoreElements()) {
System.out.println("Browse [" + enumeration.nextElement() + "]");
}
if ((Integer)obj >= 6) {
int count = Integer.valueOf(msg.getStringProperty("JMSXDeliveryCount"));
if (count > 2) {
System.out.println("********** max rollback");
userTxn.commit();
} else {
System.out.println("********** rollback");
userTxn.setRollbackOnly();
}
} else {
System.out.println("********** commit");
userTxn.commit();
}
} else {
}
} catch (Exception ex) {
ex.printStackTrace();
throw new EJBException("Transaction failed: " + ex.getMessage());
} catch (Throwable t) {
}
}
I'm using the .net client for rabbitMQ in my asp.net core webApi. I'm connecting to an exchange, declaring a queue and then start consuming it through a channel. The problem here is that when I publish a "large" number of messages at the same time to this specific queue, the consuming performance stays very low (4 messages per second, approximately).
I already searched for some configurations that could improve the consuming performance but none of them was actually effective and I'm starting to think that maybe I misunderstood the correct use of rabbitMQ on this case. I tried to increase the number of opened channels and consumer instances and it improved a little bit but nothing close to what I expected from rabbitMQ. I also tried to increase the prefetch quantity but got no explicit improvements on that.
Here is my piece of code responsible for the consumption (before my modifications to improve the performance):
public void Receive(string hostName, string queueName, string type, string routingKey, string exchange)
{
//RabbitMQ configuration
var userName = _configuration["Messaging:UserName"];
var password = _configuration["Messaging:Password"];
var prefetchQuantity = _configuration["Messaging:PrefetchQuantity"];
var factory = new ConnectionFactory() { HostName = hostName, UserName = userName, Password = password };
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.BasicQos(0, Convert.ToUInt16(prefetchQuantity), false);
//Declaring the exchange
channel.ExchangeDeclare(exchange, ExchangeType.Direct);
//Declaring the queue and creating its routing key bindings
channel.QueueDeclare(queueName, true, false, false, null);
channel.QueueBind(queueName, exchange, routingKey);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, e) =>
{
try
{
mediatorHandler.Handle(model, e, _mediator);
channel.BasicAck(e.DeliveryTag, false);
}
catch (Exception exception)
{
Console.WriteLine(exception);
channel.BasicNack(e.DeliveryTag, false, true);
}
};
channel.BasicConsume(queue: queueName,
autoAck: false,
consumer: consumer);
}
After the modifications (more channels, more consumers and prefetch count):
public void Receive(string hostName, string queueName, string type, IEnumerable<string> routingKeys, string exchange)
{
//Initializes the MediatorHandler`s factory
InitializeFactory();
var mediatorHandler = _mediatorHandlers[type];
//RabbitMQ configuration
var userName = _configuration["Messaging:UserName"];
var password = _configuration["Messaging:Password"];
var numberOfConsumers = int.Parse(_configuration["Messaging:NumerOfConsumers"]);
var channels = int.Parse(_configuration["Messaging:Channels"]);
var factory = new ConnectionFactory() { HostName = hostName, UserName = userName, Password = password };
var connection = factory.CreateConnection();
for (int i = 1; i <= channels; i++)
{
var channel = connection.CreateModel();
var prefetchQuantity = _configuration["Messaging:PrefetchQuantity"];
channel.BasicQos(0, Convert.ToUInt16(prefetchQuantity), false);
//Declaring the exchange
channel.ExchangeDeclare(exchange, ExchangeType.Direct);
//Declaring the queue and creating its routing key bindings
channel.QueueDeclare(queueName, true, false, false, null);
foreach (var routingKey in routingKeys)
{
channel.QueueBind(queueName, exchange, routingKey);
}
for (int j = 1; j <= numberOfConsumers; j++)
{
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, e) =>
{
try
{
mediatorHandler.Handle(model, e, _mediator);
channel.BasicAck(e.DeliveryTag, false);
}
catch (Exception exception)
{
Console.WriteLine(exception);
channel.BasicNack(e.DeliveryTag, false, true);
}
};
channel.BasicConsume(queue: queueName,
autoAck: false,
consumer: consumer);
}
}
}
How can I improve the consuming performance in this case?
Thanks!
I was try to send message to the MQ Server using the MQ Client
The error is:- A WebSphere MQ Error occurred : Completion Code 2 Reason Code 2058.I know this reason code because of the wrong Queue Manager Name..But the Queue Manager Name is correct...
After installed the WebSphere MQ Client I just run the command:
SET MQSERVER=QM_ORANGE/TCP/IPADDRESS(PORT NUMBER)
and run this program
public class MQSample {
// code identifier
static final String sccsid = "#(#) MQMBID sn=p750-002-131001_DE su=_FswqMCqGEeOZ3ui-rZDONA pn=MQJavaSamples/wmqjava/MQSample.java";
// define the name of the QueueManager
private static final String qManager = "QM_ORANGE";
// and define the name of the Queue
private static final String qName = "Q1";
/**
* Main entry point
*
* #param args - command line arguments (ignored)
*/
public static void main(String args[]) {
try {
// Create a connection to the QueueManager
System.out.println("Connecting to queue manager: " + qManager);
MQQueueManager qMgr = new MQQueueManager(qManager);
// Set up the options on the queue we wish to open
//int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT;
int openOptions = MQConstants.MQOO_OUTPUT;
// int openOptions1 = MQConstants.MQOO_INPUT_AS_Q_DEF;
// Now specify the queue that we wish to open and the open options
System.out.println("Accessing queue: " + qName);
MQQueue queue = qMgr.accessQueue(qName, openOptions);
//MQQueue queue1 = qMgr.accessQueue(qName, openOptions1);
// Define a simple WebSphere MQ Message ...
MQMessage msg = new MQMessage();
// ... and write some text in UTF8 format
msg.writeUTF("Hello, World!");
// Specify the default put message options
MQPutMessageOptions pmo = new MQPutMessageOptions();
// Put the message to the queue
System.out.println("Sending a message...");
queue.put(msg, pmo);
//
openOptions = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING
+ MQC.MQOO_INPUT_SHARED;
queue = qMgr.accessQueue("QM_APPLE", openOptions,
null, // default q manager
null, // no dynamic q name
null); // no alternate user id
System.out.println("MQRead v1.0 connected.\n");
int depth = queue.getCurrentDepth();
System.out.println("Current depth: " + depth + "\n");
if (depth == 0) {
return;
}
MQGetMessageOptions getOptions = new MQGetMessageOptions();
getOptions.options = MQC.MQGMO_NO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING
+ MQC.MQGMO_CONVERT;
while (true) {
MQMessage message = new MQMessage();
try {
queue.get(message, getOptions);
byte[] b = new byte[message.getMessageLength()];
message.readFully(b);
System.out.println(new String(b));
message.clearMessage();
} catch (IOException e) {
System.out.println("IOException during GET: " + e.getMessage());
break;
} catch (MQException e) {
if (e.completionCode == 2
&& e.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) {
if (depth > 0) {
System.out.println("All messages read.");
}
} else {
System.out.println("GET Exception: " + e);
}
break;
}
}
queue.close();
//_queueManager.disconnect();
// Disconnect from the QueueManager
System.out.println("Disconnecting from the Queue Manager");
qMgr.disconnect();
System.out.println("Done!");
}
catch (MQException ex) {
System.out.println("A WebSphere MQ Error occured : Completion Code " + ex.completionCode
+ " Reason Code " + ex.reasonCode);
ex.printStackTrace();
for (Throwable t = ex.getCause(); t != null; t = t.getCause()) {
System.out.println("... Caused by ");
t.printStackTrace();
}
}
catch (java.io.IOException ex) {
System.out.println("An IOException occured whilst writing to the message buffer: " + ex);
}
return;
}
}
You have set the MQSERVER environment variable. MQ C Client understands this environment variable and accordingly connects to queue manager running on the machine specified in IP address. MQ Java does not behave in the same way.
In your application you have specified just the queue manager name in MQQueueManager constructor. This mean application wants to connect to queue manager running on the same machine via server bindings connection.
You could do as below to connect to queue manager: (change the host, port, channel and queue manager name). Note the sample is written with MQ v8 Java client.
Hashtable properties = new Hashtable<String, Object>();
properties.put(MQConstants.HOST_NAME_PROPERTY, "qm.mycomp.com");
properties.put(MQConstants.PORT_PROPERTY, 1414);
properties.put(MQConstants.CHANNEL_PROPERTY, "APP.SVRCONN");
properties.put(MQConstants.USE_MQCSP_AUTHENTICATION_PROPERTY,"true");
properties.put(MQConstants.USER_ID_PROPERTY, "myuserid");
properties.put(MQConstants.PASSWORD_PROPERTY, "passw0rd");
/**
* Connect to a queue manager
*/
MQQueueManager queueManager = new MQQueueManager("QM", properties);
Update
So you don't want to hard code connection parameters in your program? You can use the MQSERVER environment variable it self, get it, parse it and the connection parameters. You can also use a configuration file or a LDAP server to pull the connection information.
Update II
You have not read the MQ documentation at all. MQ Client is a set of libraries/jars/.net assemblies etc which expose APIs in different languages. You develop application using these APIs to communicate with queue manager. That is what you have done in your program above. Without these libraries you can't connect to a queue manager (many people think queue manager as server). When your application runs on the same machine as the queue manager, it is possible to communicate with queue manager over shared memory. But when running on different machine the communication is over TCP/IP (or SNA).
Hope this clears the confusion.
I am getting a crash course in delegates and event handlers and I have been following a tutorial on the subject and trying to plug in what I have learned into a socket server program I am creating.
I am trying to decouple my server from knowing about the AlertConnectionOpened class here:
namespace AlertConnectionOpened
{
//This is a subscriber class
public class AlertConnectionOpened
{
public void OnConnectionOpened(string message)
{
Console.WriteLine("Connection is opened");
}
}
}
So I am using a delegate in my server class to accomplish this.
namespace Server
{
public class RunServer
{
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
// Thread signal.
public ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener(int port)
{
}
//This defines the delegate
//Agreement between publisher and subscriber
//object, source of event or class publishing or sending data,
//second param is any additional data we need to send.
public delegate void ConnectionOpenEventHandler(string Message);
//Indicates something has happened and finished.
//Event defined here, based on delegate
public event ConnectionOpenEventHandler ConnectionOpened;
//Raise the Event, need a method to do this.
//Responsible for notifying subscribers
protected virtual void OnConnectionOpened()
{
if (ConnectionOpened != null)
ConnectionOpened("Connection Opened");
}
public void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
int port = 11000;
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
//backlog of how many clients to take in
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
OnConnectionOpened();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
Random rand = new Random();
content = rand.ToString();
// Echo the data back to the client.
Send(handler, content);
}
else {
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
public void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
public void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
AsynchronousSocketListener a = new AsynchronousSocketListener(0);
a.StartListening();
return 0;
}
}
}
}
Here is also my main program:
namespace AppStart
{
class ServerStart
{
static void Main(string[] args)
{
RunServer.AsynchronousSocketListener svr1 = new RunServer.AsynchronousSocketListener(11000);//publisher
//Correct the port number so a second server can open
RunServer.AsynchronousSocketListener svr2 = new RunServer.AsynchronousSocketListener(350);
svr1.StartListening();//publisher
//This creates the subscriber
var alertConnectionOpened = new AlertConnectionOpened.AlertConnectionOpened();//subsciber
//make publisher register the handler for the event.
svr1.ConnectionOpened += alertConnectionOpened.OnConnectionOpened; //POinter to method
svr2.StartListening();
Console.ReadLine();
}
}
}
From the little I understand of this my call to OnConnectionOpened();, should be showing the message that there is now a connection, but it isn't.
I want to implement a distributed priority queue without using Zookeeper?
If you know how to communicate between client and server (e.g. with TCP sockets) it should be straightforward. The server contains a thread safe implementation of the Priority Queue, hence providing an "interface". Clients connect to the server and uses this "interface".
Server
The server must provide a priority queue interface (i.e. supporting add, peek, poll, ...). Important is that these methods must be thread safe ! So we will use PriorityBlockingQueue (which is synchronized) instead of PriorityQueue.
public class Server {
private static ServerSocket server_skt;
public PriorityBlockingQueue<Integer> pq;
// Constructor
Server(int port, int pq_size) {
server_skt = new ServerSocket(port);
this.pq = new PriorityBlockingQueue<Integer>(pq_size);
}
public static void main(String argv[]) {
Server server = new Server(5555, 20); // Make server instance
while(true) {
// Always wait for new clients to connect
try {
System.out.println("Waiting for a client to connect...");
// Spawn new thread for communication with client
new CommunicationThread(server_skt.accept(), server.pq).start();
} catch(IOException e) {
System.out.println("Exception occured :" + e.getStackTrace());
}
}
}
}
And this is how CommunicationThread class would look like
public class CommunicationThread extends Thread {
private Socket client_socket;
private InputStream client_in;
private OutputStream client_out;
private PriorityBlockingQueue<Integer> pq;
public CommunicationThread(Socket socket, PriorityBlockingQueue<Integer> pq) {
try {
this.client_socket = socket;
this.client_in = client_socket.getInputStream();
this.client_out = client_socket.getOutputStream();
this.pq = pq;
System.out.println("Client connected : " + client_socket.getInetAddress().toString());
} catch(IOException e) {
System.out.println("Could not initialize communication properly. -- CommunicationThread.\n");
}
}
#Override
public void run() {
boolean active = true;
while(active) {
int message_number = client_in.read(); // Listen for next integer --> dispatch to correct method
switch(message_number) {
case -1: case 0:
// Will stop the communication between client and server
active = false;
break;
case 1:
// Add
int element_to_add = client_in.read(); // read element to add to the priority queue
pq.add(element_to_add); // Note that a real implementation would send the answer back to the client
break;
case 2:
// Poll (no extra argument to read)
int res = pq.poll();
// Write result to client
client_out.write(res);
client_out.flush();
break;
/*
* IMPLEMENT REST OF INTERFACE (don't worry about synchronization, PriorityBlockingQueue methods are already thread safe)
*/
}
}
client_in.close();
client_out.close();
}
}
This class is listening to what the client is sending.
According to what the client sent, the server knows what to do, hence there is a mini protocol. That protocol is : when the client wants to invoke a method of the distributed priority queue, he sends an integer (e.g. 2 = poll()). The server reads that integer and knows which method to invoke.
Note that sometimes sending one integer is enough (see poll() example), but not always. Think for example of add() which has to specify an argument. The server will receive 1 from the client (i.e. add()) and will read a second integer (or any other object that has to be stored in the distributed priority queue).
Client
Based on the protocol, the server is offering the client an interface (e.g. 0 = stop communication, 1 = add() , ...). The client only has to connect to the server and send messages (respecting the procotol!) to it.
A client example :
public class PQ_Client {
private static Socket skt;
private InputStream in;
private OutputStream out;
private final int _STOP_ = 0, _ADD_ = 1, _POLL_ = 2; // By convention (protocol)
PQ_Client(String ip, int port) {
try {
this.skt = new Socket(ip, port);
this.in = skt.getInputStream();
this.out = skt.getOutputStream();
System.out.println("Connected to distributed priority queue.");
} catch(IOException e) {
System.out.println("Could not connect with the distributed priority queue : " + e.getStackTrace());
}
}
// Sort of stub functions
public void stop() {
out.write(_STOP_);
out.flush();
out.close();
}
public void add(Integer el) {
out.write(_ADD_); // Send wanted operation
out.write(el); // Send argument element
// Real implementation would listen for result here
out.flush();
}
public int poll() {
out.write(_POLL_);
out.flush();
// Listen for answer
return in.read();
}
/*
* Rest of implementation
*/
}
Note that thanks to these self made "stub functions" we can make a PQ_Client object and use it as if it was a priority queue (the client/server communication is hidden behind the stubs).
String ip = "...";
int port = 5555;
PQ_Client pq = new PQ_Client(ip , port);
pq.add(5);
pq.add(2);
pq.add(4);
int res = pq.poll();
Note that by using RPC (Remote Procedure Call) it could be easier (stub function generated automatically, ...).
In fact what we implemented above is a little RPC-like mechanism, as it does nothing else then sending a message to call a procedure (e.g. add()) on the server, serializing the result (not needed for integers), send it back to the client.