Philipp Philipp - 17 days ago 5
Java Question

nodeJs and jmx (npm: jmx)

I have a problem using the jmx nodeJs package to bridge and communicate with a Java application from nodeJs (see https://www.npmjs.com/package/jmx). My code looks like that:

var jmx = require('jmx');

var jmxTester = function(host, port) {
var jmxrmi = 'service:jmx:rmi:///jndi/rmi://' + host + ':' + port + '/jmxrmi';
winston.debug('jmxrmi is: ', jmxrmi);

var client = jmx.createClient({
service: jmxrmi
});

client.on('error', function (e) {
winston.silly('Error: JMX at %s:%d', host, port, e);
client.disconnect();
});

client.on('disconnect', function (err) {
winston.silly('Successfully disconnected from client.');
});

client.on('connect', function() {
winston.silly('Successfully connected to client.');
client.disconnect();
});

client.connect();
}

module.exports = jmxTester;


Using it with:

var jmxTester = require('jmxTester');

jmxTester('localhost', 20000);


runs into several problems, independent of the fact that I have a jmx running on
localhost:2000
or if I do not have anything running.


  1. nodemon cannot restart node anymore. It just shows:

    [nodemon] restarting due to changes...


    but it doesn't actually restart. It seems like jmx is leaving something unhandled, a resource open or something, so that nodemon cannot be properly close node.

  2. I also noticed that when running the app directly with node, I have to send a kill -9, instead of a "normal" kill. If I remove the jmxFun call, everything works fine. So what is wrong with jmx?



Can anyone help me to figure out how to use jmx within nodeJs properly? So that I get a clean connect and disconnect (on error and without any errors).

Here are some sample outputs:


  1. with running JMX application on
    localhost:2000
    (doing two file changes afterwards, no restart happens):

    2016-08-04T17:20:06.423Z - debug: jmxrmi is: service:jmx:rmi:///jndi/rmi://localhost:2000/jmxrmi
    2016-08-04T17:20:06.433Z - silly: Successfully connected to client.
    2016-08-04T17:20:06.434Z - silly: Successfully disconnected from client.
    [nodemon] restarting due to changes...
    [nodemon] restarting due to changes...

  2. without an running JMX application on
    localhost:2000
    (doing two file changes afterwards, no restart happens):

    2016-08-04T17:34:28.384Z - debug: jmxrmi is: service:jmx:rmi:///jndi/rmi://localhost:2000/jmxrmi
    2016-08-04T17:34:28.390Z - silly: Error: JMX at localhost:2000 { [Error: Error running static method
    java.io.IOException: Failed to retrieve RMIServer stub: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: localhost; nested exception is:
    java.net.ConnectException: Connection refused]
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:369)
    at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    Caused by: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: localhost; nested exception is:
    java.net.ConnectException: Connection refused]
    at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:122)
    at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at javax.management.remote.rmi.RMIConnector.findRMIServerJNDI(RMIConnector.java:1955)
    at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1922)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:287)
    ... 5 more
    [...]
    [nodemon] restarting due to changes...
    [nodemon] restarting due to changes...


Answer

I found the solution for my problems, which has two reasons and I'd love to share it with others, that may find this page:

  1. The problem has to do with the node java implementation, which is used by the node jmx module. I couldn't find any explanation, but a solution is stated here: https://github.com/remy/nodemon/issues/573. So I added the following to my main.js, so that prior to binding to my process.on the java is 'used':

    var java = require('java');
    java.import("javax.management.remote.JMXConnectorFactory");
    
  2. The RMI timeouts should be reduced, otherwise node waits for an response (thanks to the sync implementation of node-jmx). Thus, you should:

    var System = java.import('java.lang.System');
    System.setProperty('sun.rmi.transport.connectionTimeout', '500');
    System.setProperty('sun.rmi.transport.tcp.handshakeTimeout', '500');
    System.setProperty('sun.rmi.transport.tcp.responseTimeout', '500');
    System.setProperty('sun.rmi.transport.tcp.readTimeout', '500');
    

    First tests showed that the value of 500 may be a little to optimistic for some timeouts. Because I get sometimes a timeout even if the JMX is available (thanks to Java RMI - Client Timeout)

Hope that helps others!

Comments