How does fallback work with socket.io? - java

I'd like to use WebSocket with Java. Problem is, my server is separated from the client by a proxy that cannot be configured. I've been searching for implementations of WebSocket with fallbacks such as long-polling. I've found socket.io but don't know how the fallback works.
Under which case does it replace WebSocket and how?
Are there other libraries like socket.io with fallbacks implementations? I would like to find one in Java, but I only found Jetty.
EDIT: does the fallback only depend on the browser's compatibility with WebSocket? What if the cause of failure is a proxy badly configured, is socket.io going to detect it as a compatibilty failure and thus switch to long-polling (or another technique)?
Answer: since v1, socket.io includes engine.io, which brings the following features:

Socket.io is one of several implementations for the websockets protocol and its main selling point (IMO) is its ease of use: you don't need to code keep-alive mechanisms or decide which transport is best, it does it for you.
So, to make it clear, socket.io doesn't replace the websocket protocol, it's a package that implements it for you.
You mentioned long-polling. That is one of the transports used by socket.io. Long Polling is HTTP based and it's basically request --> wait --> response and the wait isn't very long, as it can be dropped by load balancers on EOF or stale connections. Nevertheless, it's still useful when the websockets protocol (TCP based) isn't available and socket.io automatically re-establishes the connection for you. Notice that websockets is a relatively new protocol, ratified in 2011, so older browsers don't support it. Well, socket.io detects that and then resorts to long polling, so you don't have to "worry" about it.
A websocket connection starts with HTTP, listening on the same port. For example, http://localhost:8080 (just a silly example). Then, when it's possible, socket.io switches to ws://localhost:8080 for you.
I never had problems with network topology challenges when using socket.io, as when the HTTP port is available and using long polling / websockets is possible, it just worked for me.
One of the libraries with fallback implementation, as you mentioned, is netty-socket.io. Notice how it configures the two transports:
public class Configuration {
private ExceptionListener exceptionListener = new DefaultExceptionListener();
private String context = "/socket.io";
private List<Transport> transports = Arrays.asList(Transport.WEBSOCKET, Transport.POLLING);
private int bossThreads = 0; // 0 = current_processors_amount * 2
private int workerThreads = 0; // 0 = current_processors_amount * 2
The complete code can be found here.
Node JS has also libraries for websockets, and I mention it here just to clarify that long polling and websockets aren't the only two available transports (might be the only ones in Java):
io.set('transports', [ // enable all transports (optional if you want flashsocket)
'websocket'
, 'flashsocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
In a nutshell, socket.io attempts to make things as easy as possible for you, including not having to worry about what transports to use, as it's done under the hood for you, yet still configurable if you want.
I hope this brief explanation helps you!

Related

How can I get the enqueue and dequeue count for an ActiveMQ queue WITHIN my Java Spring app?

I have been scouring the internet for documentation on this and it's unbelievable how difficult it is to find. My goal is to create a REST endpoint where I can return queue details such as enqueue, dequeue, etc. counts for a custom dashboard I am making.
I keep seeing documentation such as this, this, and this, but I can't seem to figure out how to get these details in my actual program. I have gotten about as far as using the JMX GUI, but that really is not the direction I need to be going. Can anyone help me figure out how to get simple connection to a broker that will return these details? I really have tried to research this, but I have not been able to figure out a way to incorporate this information to my application in any meaningful away.
The way to monitor the broker is via the broker JMX endpionts and the management beans it exposes. Other means would be through the Jolokia REST API that exposes those same MBeans. One article showing how to use the Jolokia bits is here.
A brief example of using JMX with ActiveMQ is below.
// connection
String url = "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi";
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(url));
MBeanServerConnection connection = connector.getMBeanServerConnection();
// get queue size
ObjectName nameConsumers = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=myqueue");
DestinationViewMBean mbView = MBeanServerInvocationHandler.newProxyInstance(connection, nameConsumers, DestinationViewMBean.class, true);
long queueSize = mbView.getQueueSize();

STOMP heart beat tracking using java and activemq-all library

I am consuming a message feed using the below code from a third party message broker. We use the STOMP protocol and the code is developed using the activemq-all library. I have noticed that the connection is hanging occasionally (after every 1-2 weeks without any feed). So I wanted to use the heart-beat feature of STOMP protocol so I have added the heart-beat header for the stompConnection as shown below:
StompConnection stompConnection = new StompConnection();
stompConnection.open(new Socket("ABC", 1234));
HashMap<String, String> headers = new HashMap<>();
headers.put("login", "abcd");
headers.put("passcode", "defghij");
headers.put("heart-beat", "0,10000");//heart-beat header newly added
stompConnection.connect(headers);
stompConnection.subscribe("topic1", "auto");
while(true) {
StompFrame stompMessage = stompConnection.receive(10000);
String messageBody = stompMessage.getBody();
//process messageBody here
}
Now my question is that is there any way to find/trace that my application (above java client) is receiving the heart beats from the sender?
That library is a test support only tool with no support for issues other than those affecting ActiveMQ tests. Using it is risky and not recommended for any production level work. You'd be far better off using a full open source Stomp client with actual support. The track heart beats with this client you would need to drop to the socket level and track the incoming bytes directly.

Apache Camel, Netty4 endpoint as client - memory leakage

I'm quite new to Apache Camel and trying to bring some routes into action.
I have a TCP server which serves large JSON-Messages (up to ~30-50kB in size, where i do not have any control about the source size) that contain lots of measurement data which i want to process using certain additional routes that work fine.
I'm using camel 2.20 within spring-boot environment 1.5.7.
I faced the problem that if i commented out every other routes except the incoming reduced netty4 route (only from and to a counter), see below
#Bean
public RouteBuilder getRoute() {
String fromSource = String.format("netty4:tcp://%s:%d?clientMode=true&textline=true&receiveBufferSize=64000&decoderMaxLineLength=64000",sourceIp,sourcePort);
return new RouteBuilder() {
from(fromSource)
.to("metrics:counter:incomingCounter");
};
}
The route works nearly fine but consumes more and more heap-space (around 2MB every second, where there are messages served with a frequency of around 20-30Hz) until java throws java.lang.OutOfMemoryError: Java heap space.
Without any route no memory-leak was registered, as i can focus the problem to the netty-route
Any help will be appreciated.
Thanks in advance.
I found the resolution myself by debugging the code.
I forgot to set property sync=false in netty4-camel endpoint as i don't want to process message and send an answer back to the server after processing, just consuming - while sync=true (default settings) buffers all incoming data for later response which caused my "memory-leak".
The behavior of "sync" was not totally clear from the netty4-camel documentation (http://camel.apache.org/netty4.html) - i'll suggest an improvement of the documentation (will write a mail with a proposal) to make the usage a little more clearly.
Maybe this helps someone another having a similar problem.
Best

Http Websocket as Akka Stream Source

I'd like to listen on a websocket using akka streams. That is, I'd like to treat it as nothing but a Source.
However, all official examples treat the websocket connection as a Flow.
My current approach is using the websocketClientFlow in combination with a Source.maybe. This eventually results in the upstream failing due to a TcpIdleTimeoutException, when there are no new Messages being sent down the stream.
Therefore, my question is twofold:
Is there a way – which I obviously missed – to treat a websocket as just a Source?
If using the Flow is the only option, how does one handle the TcpIdleTimeoutException properly? The exception can not be handled by providing a stream supervision strategy. Restarting the source by using a RestartSource doesn't help either, because the source is not the problem.
Update
So I tried two different approaches, setting the idle timeout to 1 second for convenience
application.conf
akka.http.client.idle-timeout = 1s
Using keepAlive (as suggested by Stefano)
Source.<Message>maybe()
.keepAlive(Duration.apply(1, "second"), () -> (Message) TextMessage.create("keepalive"))
.viaMat(Http.get(system).webSocketClientFlow(WebSocketRequest.create(websocketUri)), Keep.right())
{ ... }
When doing this, the Upstream still fails with a TcpIdleTimeoutException.
Using RestartFlow
However, I found out about this approach, using a RestartFlow:
final Flow<Message, Message, NotUsed> restartWebsocketFlow = RestartFlow.withBackoff(
Duration.apply(3, TimeUnit.SECONDS),
Duration.apply(30, TimeUnit.SECONDS),
0.2,
() -> createWebsocketFlow(system, websocketUri)
);
Source.<Message>maybe()
.viaMat(restartWebsocketFlow, Keep.right()) // One can treat this part of the resulting graph as a `Source<Message, NotUsed>`
{ ... }
(...)
private Flow<Message, Message, CompletionStage<WebSocketUpgradeResponse>> createWebsocketFlow(final ActorSystem system, final String websocketUri) {
return Http.get(system).webSocketClientFlow(WebSocketRequest.create(websocketUri));
}
This works in that I can treat the websocket as a Source (although artifically, as explained by Stefano) and keep the tcp connection alive by restarting the websocketClientFlow whenever an Exception occurs.
This doesn't feel like the optimal solution though.
No. WebSocket is a bidirectional channel, and Akka-HTTP therefore models it as a Flow. If in your specific case you care only about one side of the channel, it's up to you to form a Flow with a "muted" side, by using either Flow.fromSinkAndSource(Sink.ignore, mySource) or Flow.fromSinkAndSource(mySink, Source.maybe), depending on the case.
as per the documentation:
Inactive WebSocket connections will be dropped according to the
idle-timeout settings. In case you need to keep inactive connections
alive, you can either tweak your idle-timeout or inject ‘keep-alive’
messages regularly.
There is an ad-hoc combinator to inject keep-alive messages, see the example below and this Akka cookbook recipe. NB: this should happen on the client side.
src.keepAlive(1.second, () => TextMessage.Strict("ping"))
I hope I understand your question correctly. Are you looking for asSourceOf?
path("measurements") {
entity(asSourceOf[Measurement]) { measurements =>
// measurement has type Source[Measurement, NotUsed]
...
}
}

Read timeout on a web service, but the operation still completes?

I have a Java web service client running on Linux (using Axis 1.4) that invokes a series of web services operations performed against a Windows server. There are times that some transactional operations fail with this Exception:
java.net.SocketTimeoutException: Read timed out
However, the operation on the server is completed (even having no useful response on the client). Is this a bug of either the web service server/client? Or is expected to happen on a TCP socket?
This is the expected behavior, rather than a bug. The operation behind the web service doesn't know anything about your read timing out so continues processing the operation.
You could increase the timeout of the connection - if you are manually manipulating the socket itself, the socket.connect() method can take a timeout (in milliseconds). A zero should avoid your side timing out - see the API docs.
If the operation is going to take a long time in each case, you may want to look at making this asynchronous - a first request submits the operations, then a second request to get back the results, possibly with some polling to see when the results are ready.
If you think the operation should be completing in this time, have you access to the server to see why it is taking so long?
I had similar issue. We have JAX-WS soap webservice running on Jboss EAP6 (or JBOSS 7). The default http socket timeout is set to 60 seconds unless otherwise overridden in server or by the client. To fix this issue I changed our java client to something like this. I had to use 3 different combinations of propeties here
This combination seems to work as standalone java client or webservice client running as part of other application on other web server.
//Set timeout on the client
String edxWsUrl ="http://www.example.com/service?wsdl";
URL WsURL = new URL(edxWsUrl);
EdxWebServiceImplService edxService = new EdxWebServiceImplService(WsURL);
EdxWebServiceImpl edxServicePort = edxService.getEdxWebServiceImplPort();
//Set timeout on the client
BindingProvider edxWebserviceBindingProvider = (BindingProvider)edxServicePort;
BindingProvider edxWebserviceBindingProvider = (BindingProvider)edxServicePort;
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.internal.ws.request.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.internal.ws.connect.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.ws.request.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("com.sun.xml.ws.connect.timeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("javax.xml.ws.client.receiveTimeout", connectionTimeoutInMilliSeconds);
edxWebserviceBindingProvider.getRequestContext().put("javax.xml.ws.client.connectionTimeout", connectionTimeoutInMilliSeconds);

Categories