0

i am trying to use cassandra as database for an app i am working on. The app is a Netbeans platform app. In order to start the cassandra server on my localhost i issue Runtime.getRuntime().exec(command) where command is the string to start the cassandra server and then i connect to the cassandra sever with the datastax driver. However i get the error:

com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query   failed (tried: /127.0.0.1:9042 (com.datastax.driver.core.TransportException: [/127.0.0.1:9042]  Cannot connect))
at com.datastax.driver.core.ControlConnection.reconnectInternal(ControlConnection.java:199)
at com.datastax.driver.core.ControlConnection.connect(ControlConnection.java:80)
at com.datastax.driver.core.Cluster$Manager.init(Cluster.java:1154)
at com.datastax.driver.core.Cluster.getMetadata(Cluster.java:318)
at org.dhviz.boot.DatabaseClient.connect(DatabaseClient.java:43)
at org.dhviz.boot.Installer.restored(Installer.java:67)
....

i figure it out that the server requires some time to start so i have added the line Thread.sleep(MAX_DELAY_SERVER) which seem to resolve the problem.

Is there any more elegant way to sort this issue? Thanks.

Code is below.

public class Installer extends ModuleInstall {

private final int MAX_DELAY_SERVER = 12000;

//private static final String pathSrc = "/org/dhviz/resources";
@Override
public void restored() {

    /*
     -*-*-*-*-*DESCRIPTION*-*-*-*-*-*
     IMPLEMENT THE CASSANDRA DATABASE
     *********************************
     */
    DatabaseClient d = new DatabaseClient();
    // launch an instance of the cassandra server 
    d.loadDatabaseServer();


    /*wait for MAX_DELAY_SERVER milliseconds before launching the other instructions. 
    */
    try {
        Thread.sleep(MAX_DELAY_SERVER);
        Logger.getLogger(Installer.class.getName()).log(Level.INFO, "wait for MAX_DELAY_SERVER milliseconds before the connect database");
    } catch (InterruptedException ex) {
        Exceptions.printStackTrace(ex);
        Logger.getLogger(Installer.class.getName()).log(Level.INFO, "exeption in thread sleep");
    }

    d.connect("127.0.0.1");

}
}



public class DatabaseClient {

private Cluster cluster;
private Session session;
private ShellCommand shellCommand;
private final String defaultKeyspace = "dhviz";

final private String LOAD_CASSANDRA = "launchctl load    /usr/local/Cellar/cassandra/2.1.2/homebrew.mxcl.cassandra.plist";

final private String UNLOAD_CASSANDRA = "launchctl unload /usr/local/Cellar/cassandra/2.1.2/homebrew.mxcl.cassandra.plist";

public DatabaseClient() {
    shellCommand = new ShellCommand();

}

public void connect(String node) {
//this connect to the cassandra database

    cluster = Cluster.builder()
            .addContactPoint(node).build();
//  cluster.getConfiguration().getSocketOptions().setConnectTimeoutMillis(12000);
    Metadata metadata = cluster.getMetadata();
    System.out.printf("Connected to cluster: %s\n",
            metadata.getClusterName());
    for (Host host
            : metadata.getAllHosts()) {
        System.out.printf("Datatacenter: %s; Host: %s; Rack: %s\n",
                host.getDatacenter(), host.getAddress(), host.getRack());

    }

        session = cluster.connect();


    Logger.getLogger(DatabaseClient.class.getName()).log(Level.INFO, "connected to server");
}

public void loadDatabaseServer() {
    if (shellCommand == null) {

        shellCommand = new ShellCommand();

    }
    shellCommand.executeCommand(LOAD_CASSANDRA);
    Logger.getLogger(DatabaseClient.class.getName()).log(Level.INFO, "database cassandra loaded");
}

public void unloadDatabaseServer() {
    if (shellCommand == null) {

        shellCommand = new ShellCommand();

    }

    shellCommand.executeCommand(UNLOAD_CASSANDRA);

    Logger.getLogger(DatabaseClient.class.getName()).log(Level.INFO, "database cassandra unloaded");
}

}
user3498704
  • 23
  • 1
  • 4

2 Answers2

1

If you are calling cassandra without any parameters in Runtime.getRuntime().exec(command) it's likely that this is spawning cassandra as a background process and returning before the cassandra node has fully started and is listening.

I'm not sure why you are attempting to embed cassandra in your app, but you may find using cassandra-unit useful for providing a mechanism to embed cassandra in your app. It's primarily used for running tests that require a cassandra instance, but it may also meet your use case.

The wiki provides a helpful example on how to start an embedded cassandra instance using cassandra-unit:

EmbeddedCassandraServerHelper.startEmbeddedCassandra();

In my experience cassandra-unit will wait until the server is up and listening before returning. You could also write a method that waits until a socket is in use, using logic opposite of this answer.

Community
  • 1
  • 1
Andy Tolbert
  • 11,418
  • 1
  • 30
  • 45
  • Hi Andy. thanks for your help. just a clarification. I am fairly new to coding and very green at databases. I have an app that will produce yearly time series for many objects so i thought i would save this in Cassandra instead of having them all in memory. Cassandra, in my mind, will be running as a server on the machine running the app. The problem is exactly what you said. The server is not listening yet before the connect command is issued. I am not sure however how i can use the example you mention. Could you give some more pointers? Thanks. – user3498704 Jan 16 '15 at 10:18
  • By the example I mention, are you referring to EmbeddedCassandraHelper or the link to the answer I posted that shows how to check whether or not sockets are listening? EmbeddedCassandraHelper simply starts an embedded cassandra instance within your JVM, that may not be something you want since it shares resources with everything else your app is doing. The answer I linked might not be a good example now that I think about it. It's better to try to open a socket to localhost:9042 instead of using ServerSocket. If you can't open a connection to localhost:9042, cassandra is not listening. – Andy Tolbert Jan 16 '15 at 16:07
  • Thanks Andy. I did not manage to get the port code to work but i took inspiration from it and changed few lines in my code. Thanks for your help ! – user3498704 Jan 30 '15 at 11:23
0

I have changed the code to the following taking inspiration from the answers below. Thanks for your help!

cluster = Cluster.builder()
            .addContactPoint(node).build();

    cluster.getConfiguration().getSocketOptions().setConnectTimeoutMillis(50000);

    boolean serverConnected = false;
    while (serverConnected == false) {
        try {
            try {
                Thread.sleep(MAX_DELAY_SERVER);

            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            }
            cluster = Cluster.builder()
                    .addContactPoint(node).build();

            cluster.getConfiguration().getSocketOptions().setConnectTimeoutMillis(50000);
            session = cluster.connect();
            serverConnected = true;

        } catch (NoHostAvailableException ex) {
            Logger.getLogger(DatabaseClient.class.getName()).log(Level.INFO, "trying connection to cassandra server...");
            serverConnected = false;
        }

    }                                                   
user3498704
  • 23
  • 1
  • 4