I'm trying to implement some Websocket functionality for my web app running on Tomcat 7. I'm using the following tech:
(server) Spring Websocket + Spring Messaging
(client) SockJS + Stomp.js
I'm following this guide (roughly): http://g00glen00b.be/spring-angular-sockjs/
My configuration is similar to the guide, but I'll add some snippets of my code here:
Client:
s.socket = new SockJS('http://localhost:8181/.cckiosk/socket/test');
//s.socket = new SockJS('http://localhost:8181/.cckiosk/socket/test', {}, { transports: ['xhr-polling'] });
s.client = Stomp.over(s.socket);
s.client.connect({}, onConnect);
s.client.onclose = onDisconnect;
Server:
#Configuration
#ComponentScan
#EnableWebSocketMessageBroker
public class ModuleWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry broker) {
//Prefix for messages FROM server TO client
broker.enableSimpleBroker("/client");
//Prefix for messages FROM client TO server
broker.setApplicationDestinationPrefixes("/server");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket/test").setAllowedOrigins("*").withSockJS();
}
}
Controller:
#MessageMapping("/socket/test")
#SendTo("/client/message")
public GenericMessage doSample(GenericMessage msg) {
log.info("doSample: " + JsonUtil.jsonify(msg));
return new GenericMessage(msg.getId(), msg.getMessage(), new Date());
}
I have everything set up in a vanilla Spring app, and everything works great.
However, when I port the same code over to a Magnolia module, the code stops working and I can see the following errors:
Client-side error:
Server-side error:
2015-09-19 16:28:43,412 DEBUG eb.socket.handler.LoggingWebSocketHandlerDecorator: New WebSocketServerSockJsSession[id=tde1syjd]
2015-09-19 16:28:43,413 DEBUG eb.socket.handler.LoggingWebSocketHandlerDecorator: Transport error in WebSocketServerSockJsSession[id=tde1syjd]
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:196)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at org.apache.coyote.http11.upgrade.BioServletInputStream.doRead(BioServletInputStream.java:37)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.read(AbstractServletInputStream.java:129)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:47)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:203)
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:93)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
It's actually either Connection Reset or Broken Pipe.
Changing the transport protocol to a non-websocket one (e.g. xhr-polling) also doesn't help.
Any idea what could be in Magnolia that's causing a long-lived Websocket session to have its connection closed?
The solution lay in simply bypassing the Magnolia filter chain altogether.
I just needed to create a global bypass object in Magnolia admincentral: Configuration > server/filters/bypasses
class: info.magnolia.StartsWithURIVoter
pattern: /socket
And the connection doesn't reset or get interrupted anymore.
In Mangolia 5 it is 'info.magnolia.voting.voters.URIStartsWithVoter', instead of 'info.magnolia.StartsWithURIVoter'
Related
I have an application with websocket and stomp as the protocol for messaging. I followed the official spring documentation in order to create this application. After a couple of days, i got a report that the host in which the application is running received an alert from Prometheus called FdExhaustionClose, which from my understanding means that some connections are not being properly closed.
The application is running in kubernetes (linux) and we are using RabbitMQ as the message broker.
How can i fix this ? Running locally i realized that the total number of connections since the application started actually matches the number of file descriptors unclosed.
I checked the logs in production and the broker status was printing this:
WebSocketSession[42 current WS(42)-HttpStream(0)-HttpPoll(0), 52766 total, 0 closed abnormally
And a simply lsof -p PID | wc -l returned the number 52752
WebSocketConfig
//...
#Configuration
public class WebSocketChatConfig extends DelegatingWebSocketMessageBrokerConfiguration {
#Autowired
private ApplicationProperties properties;
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/wss").setAllowedOrigins("*");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
RabbitMqProperties rabbitProperties = properties.getRabbitmq();
ReactorNettyTcpClient<byte[]> client = new ReactorNettyTcpClient<>(tcpClient -> tcpClient
.host(rabbitProperties.getHost())
.port(rabbitProperties.getPort())
.option(ChannelOption.SO_TIMEOUT, 3600000)
.noProxy()
.secure(SslProvider.defaultClientProvider()), new StompReactorNettyCodec());
registry.setApplicationDestinationPrefixes("/app", "/topic", "/chat");
registry.enableStompBrokerRelay("/topic")
.setRelayHost(rabbitProperties.getHost())
.setRelayPort(rabbitProperties.getPort())
.setVirtualHost(rabbitProperties.getUsername())
.setSystemLogin(rabbitProperties.getUsername())
.setSystemPasscode(rabbitProperties.getPassword())
.setClientLogin(rabbitProperties.getUsername())
.setClientPasscode(rabbitProperties.getPassword()).setTcpClient(client);
}
}```
After some research i found out that the problem was related to the package reactor-netty, apparently there was a leak in version 0.9.8, the leak got fixed in version 0.9.9
I'm completly new about Hystrix, however I need to monitor metrics from it.
So far I got a stand alone that display/run the Hystrix Dashboard.
In my project I add the dependencies;
compile(group:"com.netflix.hystrix", name:"hystrix-metrics-event-stream", version:'1.5.5')
compile(group:"org.springframework.cloud", name:"spring-cloud-starter-hystrix-dashboard", version:'1.1.5.RELEASE')
compile(group:"org.springframework.boot", name:"spring-boot-starter-actuator", version:'1.4.0.RELEASE')
compile(group:"org.springframework.cloud", name:"spring-cloud-starter-hystrix", version:'1.1.5.RELEASE')
Also in my SpringConfig I add
#EnableHystrix
public class MyAppConfig {
#Bean
public ServletRegistrationBean servletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new HystrixMetricsStreamServlet(), "/hystrix.stream");
return registration;
}
}
I succesfully boot the services I can check if it is running by localhost:8080/health and get the answer.
When I add localhost:8080/hystrix.stream and hit the button Monitor Streams in the Hystrix Dashboard for a brief time it says "Loading..." but then I get "Unable to connect to Command Metric Stream."
Also I got this in the dashboard console;
17:19:26.858 [vert.x-eventloop-thread-0] INFO c.g.k.h.c.s.d.HystrixDashboardProxyConnectionHandler - Proxing request to http://localhost:8080/hystrix.stream
17:19:31.879 [vert.x-eventloop-thread-0] ERROR c.g.k.h.c.s.d.HystrixDashboardProxyConnectionHandler - Proxying request
java.util.concurrent.TimeoutException: The timeout period of 5000ms has been exceeded
at io.vertx.core.http.impl.HttpClientRequestBase.timeout(HttpClientRequestBase.java:155)
at io.vertx.core.http.impl.HttpClientRequestBase.handleTimeout(HttpClientRequestBase.java:140)
at io.vertx.core.http.impl.HttpClientRequestBase.lambda$setTimeout$0(HttpClientRequestBase.java:100)
at io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:782)
at io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:753)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:316)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:418)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:440)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873)
at java.lang.Thread.run(Thread.java:745)
17:19:31.894 [vert.x-eventloop-thread-0] ERROR c.g.k.h.c.s.d.HystrixDashboardProxyConnectionHandler - Proxying request
io.vertx.core.VertxException: Connection was closed
at io.vertx.core.http.impl.ClientConnection.handleClosed(ClientConnection.java:396)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:314)
at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:190)
at io.vertx.core.net.impl.VertxHandler.channelInactive(VertxHandler.java:97)
Finally trying to make a curl localhost:8080/hystrix.stream isn't responding at all.
I'm not sure if missing something anyone could give me a hint please?
Regards.
I think that you are missing #HistrixDashBoard annotation over your main class
If you are using actuator, your stream should be here:
http://localhost:8080/actuator/hystrix.stream
I am trying to consume below public web service using Eclipse.
http://www.webservicex.com/globalweather.asmx?wsdl
When I execute in the java client it gives the error;
java.net.ConnectException: Connection timed out: connect
Below is the simple client program;
public class ClientTest1
{
public static void main(String[] args)
{
GlobalWeatherSoapProxy obj1 = new GlobalWeatherSoapProxy();
try
{
System.out.println(obj1.getCitiesByCountry("Japan"));
}
catch(Exception e1)
{
System.out.println(+e1.getMessage());
}
}
}
However strangely this works fine when consumed through SOAP UI. Hence I assume this is something to do with Eclipse configuration.
Thank you in advance for any help.
Eclipse has nothing to do with it. Your code is executed by the JVM, even if your development environment is Eclipse. A connection time out means that your client is not able to connect with the endpoint.
You have auto-generated the client proxy in some way getting GlobalWeatherSoapProxy. This class will obtain the reference to endpoint by loading WSDL. Alternatively url can be provided by code. Review the content of that class to see how endpoint URL is loaded
You should see something like (check this full example)
URL url = new URL("http://localhost:9999/ws/hello?wsdl");
QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
My smartphone collects GPS, Bluetooth log, then periodically send the data to server.
My server continuously receive the data by using Restlet.
However i encounter a error which i have never seen before and Google does not give any solution or hints. (my server has worked well for the past few days.)
Following message is errors i encountered.
Unable to run the following server-side task: sun-net.httpserver.ServerImpl$Exchange#81a5dc
Unable to run the following server-side task: sun-net.httpserver.ServerImpl$Exchange#~~~~~~
Unable to run the following server-side task: sun-net.httpserver.ServerImpl$Exchange#~~~~~~
Following is my code.
RestletServerMain.java
public void restServer(){
try{
Component component = new Component();
component.getServers().add(Protocol.HTTP, Integer.parseInt(Common.SERVER_PORT));
component.getDefaultHost().attach(new ServerApplication());
component.start();
}catch(Exception e){
e.printStackTrace();
}
}
ServerApplication.java
public class ServerApplication extends Application {
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/dataprocessing1", xxx.class);
router.attach("/dataprocessing2", yyy.class);
return router;
}
It could be interesting to try the jetty extension (org.restlet.extends.jetty) of Restlet (instead of the default one).
Just add the corresponding jar file in your classpath and Jetty will be used as underlying server for your application.
Hope it will fix your issue.
Thierry
I am trying to get started with WebSockets, and trying to write a simple application to send messages back and forth via a websoket.
However, it looks like the socket that I am trying to create never gets connected. Why can that be?
Below is the code of my WebSockets class. When .onConnect() is called, it logs:
I am socket, I was connected. Am i connected? - false
Update: in JavaScript, where I create the socket in question, the readyState is 1, which means "socket open, communication is possble".
import a.b.Misc; //writes logs.
import com.sun.grizzly.websockets.BaseServerWebSocket;
import com.sun.grizzly.websockets.DataFrame;
import com.sun.grizzly.websockets.WebSocketListener;
public class ChatWebSocket_v2 extends BaseServerWebSocket {
private String user;
public ChatWebSocket_v2(WebSocketListener... listeners) {
super(listeners);
}
public String getUser() {
if (user == null) {
Misc.print("User is null in ChatWebSocket");
throw new NullPointerException("+=The user is null in chat web socket");
}
return user;
}
public void setUser(String user) {
Misc.print("Just set user: " + user);
this.user = user;
}
#Override
public void onMessage(String message) {
Misc.print(message +"\n");
}
#Override
public void onMessage(byte[] message) {
Misc.print(new String(message) +" << Bytes\n");
}
#Override
public void onConnect() {
Misc.print("I am socket, i was connected. Am i connected? - " + this.isConnected());
}
#Override
public void onClose(DataFrame df) {
Misc.print("I am socket, i was closed");
}
}
If you're just trying to make a connection somewhere, you might want to try this instead. There is a live working demo and you can download the javascript code and play with it yourself. Note that the javascript code only works if you have it installed on a server (due to browser security because it's 'fancy'.) There is also a step by step browser-based client tutorial in the works that I will post as soon as it's ready. Most proxy servers haven't been upgraded to handle websockets so they will screw up connection request and most people won't be able to connect to websocket servers from work. Firefox 7 (release) or Google Chrome 14 or later support the latest version of the websocket protocol that the demo server runs.
If you want to try to get the grizzly demo working, you might have some debugging to do and maybe I'll help with that. Note that in comments below the article, other people said they couldn't get it working either and I haven't found any follow up. At this point it seems no better than the echo app above even if we do get it running and is possibly overly complicated and underly documented if you're just trying to get started. But if you want to try to get it running, you should 'git' the latest version of the code here, which was at least committed recently and may be fixed.
Then make sure that app.url in the application javascript file is set to your installation directory. His is hard-coded as:
url: 'ws://localhost:8080/grizzly-websockets-chat/chat',
If you're using Firefox 7, the javascript needs to be modified to use the Moz prefix, for example:
if (typeof MozWebSocket != "undefined") { // window.MozWebSocket or "MozWebSocket" in window
ok
} else if (window.WebSocket) { // he uses if ("WebSocket" in window)
ok
} else {
do your print "browser doesn't support websockets"
}
.... then if the browser supports websockets
websocket = new WebSocket(app.url); or
websocket = new MozWebSocket(app.url);
// depending on which it is.
The HLL websocket server demo code has this all sorted out.
(another) UPDATE: As I work through grizzly myself, I found on the Quick Start in the glassfish admin console, there's a hello sample that's pretty easy to set up and run. You'll find instructions there. The sample directory also contains a war file named: websocket-mozilla; so I guess its supposed to use websockets. Someone who's familiar with jsp should review the source code. All I can see is that it's using an http session. No mention of a websocket at all. It's a lot like the hello sample.