user3498704
user3498704

Reputation: 23

cassandra single node connection error

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");
}

}

Upvotes: 0

Views: 2938

Answers (2)

user3498704
user3498704

Reputation: 23

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;
        }

    }                                                   

Upvotes: 0

Andy Tolbert
Andy Tolbert

Reputation: 11638

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.

Upvotes: 1

Related Questions