0

UPDATE It seems that in org.glassfish.tyrus.core.BaseContainer in the constructor, these two lines run super slow:

this.managedExecutorService = lookupManagedExecutorService();
this.managedScheduledExecutorService = lookupManagedScheduledExecutorService();

What is the deal with the mention of Android in the comments of both methods, am I using the wrong code for Java that is aimed at Desktops?


I am using the code exactly as it is from:

Tyrus Websocket Documentation: 1.1.2 Client Endpoint

Somehow it takes about 10 seconds to connect, specifically at this line when I run Eclipse's debugger:

ClientManager client = ClientManager.createClient();

Could it be related to this? Potentially similar Stack Overflow Question

I am really lost, I feel like I am a rare outlier trying to use websockets with a Java client as opposed to a browser with Javascript.

Community
  • 1
  • 1
smuggledPancakes
  • 9,881
  • 20
  • 74
  • 113
  • Remember running in debug mode can slow things down; the optimizations might not be working their hardest, garbage collection, etc. – D. Ben Knoble May 22 '15 at 22:53
  • 1
    Try Tyrus 1.10. #createClient should not take significant amount of time, #connectToServer could (server / network issues) – Pavel Bucek May 23 '15 at 17:54
  • @Pavel, I am using tyrus-standalone-client-1.10.jar – smuggledPancakes May 26 '15 at 21:45
  • ah, ok. I saw 1.1.2, but that's actually link pointing to 1.9 documentation ;) anyway, can you do some more comprehensive measurements? you could just try to call ClientManager.createClient few thousand times and see how long it will take (without attached debugger). It could take some time to process the classpath if its super long.. – Pavel Bucek May 27 '15 at 08:58
  • I just noticed your UPDATE; that would mean the time is spent in "final Class> aClass = Class.forName("javax.naming.InitialContext");", which is expected to fail on Android - is this the cause? – Pavel Bucek May 27 '15 at 08:59
  • lines 180 and 200 in BaseContainer.java take about six seconds each to perform a Method.invoke() call. I cannot figure out why and I do not see anything on Google about these calls taking too long... – smuggledPancakes May 27 '15 at 16:11
  • What I need is for the JVM to not take 5-6 seconds to try and find each services, I'd rather they just fail immediately or not try at all. The code for finding those services is in BaseContainer and I cannot override it :( – smuggledPancakes May 27 '15 at 18:48
  • Another update, it seems that when I run my code with no JNDI context, it works fast. There is a "no initial context" type exception and it does not hang for five seconds. When I have a faulty JNDI context it hangs... the trouble is that I cannot easily get around the faulty JNDI context outside of production. I will have to figure something out. – smuggledPancakes May 27 '15 at 21:17
  • 1
    Try `System.setProperty(javax.naming.InitialContext.INITIAL_CONTEXT_FACTORY, "javax.naming.spi.InitialContextFactory");` before calling `createClient`. It should fail the JNDI lookup fast. In my tests, the client is created in less than 100 ms. (both the Grizzly and Jdk variant). – vanOekel May 27 '15 at 22:10
  • @vanOekel, if you turn your comment into an answer I will accept it. It works ☜(⌒▽⌒)☞ – smuggledPancakes May 28 '15 at 16:26

1 Answers1

1

So the cause of the troubles is the initialization of an InitialContext by Tyrus in order to re-use a (scheduled) executor service if one is available. Normally this fails fast if none is available (and this is logged as a debug-message, see further on), but in this case it failed only after trying to initialize a INITIAL_CONTEXT_FACTORY that could not work. To override this behavior, call
System.setProperty(javax.naming.InitialContext.INITIAL_CONTEXT_FACTORY, "javax.naming.spi.InitialContextFactory")
before creating a client. The initial InitialContext will then try to create an instance of an interface and this fails fast.

The problems could probably be found earlier with verbose logging. Tyrus does not do a lot of (debug) logging but in this case a setup with jul over logback could have shown an early indication of the underlying troubles. As a general rule: always ensure you can view trace/debug logging when running into weird problems.

As for the Android comments in the source code: this is just the platform where the incompatability with the "JDK8 compact2 profile" was noticed and it was resolved by not importing the javax.naming.InitialContext class directly (since apparently it does not exist in the compact2 profile) but using reflection instead (see also TYRUS-242).

If you are creating a purely Java Websocket client, consider using the JDK 7 client. The JDK 7 client bundle (org.glassfish.tyrus:tyrus-container-jdk-client:1.10) is considerably smaller as the default one (org.glassfish.tyrus.bundles:tyrus-standalone-client:1.10).

I also felt like I an outlier when I started using websockets with a Java client (I choose the Jetty websocket client API implementation). I also started using Tomcat embedded more (for example basic-jsp-embed). When combining these techniques, you get a powerful ("full duplex") network solution (more akin to peer-to-peer instead of client-server). Hopefully it will catch on.
One caveat to remember is that some firewalls will drop connections (that look like http-connections) after 30 minutes (even when the connection is in use). So for a stable connection, make sure the client sends regular ping-messages to ensure a healthy connection and creates a new connection within/every 30 minutes.

Community
  • 1
  • 1
vanOekel
  • 6,358
  • 1
  • 21
  • 56