Using HeavyAI connector in NodeJS application

Comments

9 comments

  • Avatar
    Candido Dessanti

    Hello Lee Jenkins

    We have provided some samples on how to use the connector without relying on the browser.

    You can access them via this link: https://github.com/heavyai/heavyai-connector/blob/master/test/integration.spec.js

    Please let me know if these examples meet your requirements.

    Best regards,
    Candido

    1
    Comment actions Permalink
  • Avatar
    Candido Dessanti

    Hi Lee,

    Our Front-End Engineer re-tested version 7.0 of the connector using Node.js to ensure that it works in both successful and failed scenarios. They found that everything is functioning as intended.

    The code used:

    const Connector = require("@heavyai/connector/dist/node-connector.js").DbCon;
    
    const hostname = process.env.HOSTNAME || "kali.mapd.com"
    const protocol = process.env.PROTOCOL || "https"
    const port = process.env.PORT || "10043"
    const database = process.env.DATABASE || "mapd"
    const username = process.env.USER_NAME || "admin"
    const password = process.env.PASSWORD || "HyperInteractive"
    
    const config = {
      hostname,
      protocol,
      port,
      database,
      username,
      password,
    }
    const connector = new Connector()
    .protocol(config.protocol)
    .host(config.hostname)
    .port(config.port)
    .dbName(config.database)
    .user(config.username)
    .password(config.password);
    
    console.log(`connect to heavydb...`);
    connector.connect((err, session) => {
        if (err) {
          console.error(err)
          throw err
        }
        console.log(`connect succeeded! ${session.sessionId()}`);
        
    });

    This test rules out any problems with the connector, so it's possible that we are facing an infrastructure issue on your side. For reference, here is the output of the environment they used for testing.

    A summary of component version with a successful connection.

    Using a not-existent host, so a failure.

    Do this helps? 

    Candido

    1
    Comment actions Permalink
  • Avatar
    Candido Dessanti

    Hi,

    I will ask to front-end engineers and I will come back to this thread

    0
    Comment actions Permalink
  • Avatar
    Lee Jenkins

    Hi Candido.

    Thanks for posting that example. I tried following the steps in the example, but my example nodejs program still cannot connect to the database. My tests are described below. Could you take a look at what I am doing, or forward this to someone who might be able to help? Whatever I'm missing, it is eluding me.

    Regards,
    Lee Jenkins

    -----------------------------------------------------------

    Here is a summary of what I have tried:

    • created an env file with host/port/user/etc. variables.
    • created a shell script (below) to execute a query, using the CLI heavysql to connect with env vars
    • created a nodejs script (below) to execute the same query, using the heavyai-connector example code and the env vars

    The shell script that calls heavysql can connect and execute the query very quickly. The nodejs script attempts to connect, but the callback function is never executed. I expected the callback function to be called with either an error or a session.

    As an experiment, I also tried calling `connector.connectAsync()` instead of `connector.connect()`. The result was effectively the same: the promise was never resolved or rejected. The script just hung at the call to `connectAsync()`.

    For negative test cases, I changed to port number in the env file and ran both scripts again. Both scripts immediately reported connection errors. So that tells me that the nodejs connector is trying to connect. But unlike the command-line heavysql, the nodejs script is hanging during the connect.

    Here is a log of the tests:

    $ node --version
    v18.14.0
    $ !grep
    grep version node_modules/@heavyai/connector/package.json
      "version": "7.0.0",
    $ heavysql --version
    HeavySQL Version: 6.4.0-20230201-87f6fa37b4
    $ time ./heavysql-test
    DB_PROTOCOL is 'mapd'
    connect with: heavysql myDatabase  -s remote-host --port 6274 -u myname -p mypasswd
    User myname connected to database myDatabase
    EXPR$0
    1071552723
    User myname disconnected from database myDatabase

    real    0m0.381s
    user    0m0.003s
    sys     0m0.004s
    $ time node test-me.js
    config hostname = 'remote-host'
    config protocol = 'mapd'
    config port_num = '6274'
    config database = 'myDatabase'
    config username = 'myname'
    config password = 'mypasswd'
    connect to heavydb...
    ^C

    real    0m9.997s
    user    0m0.255s
    sys     0m0.040s
    $

    Here is the nodejs script test-me.js:

    const Connector = require("@heavyai/connector/dist/node-connector.js").DbCon;

    const config = {
        hostname: process.env.DB_HOSTNAME,
        protocol: process.env.DB_PROTOCOL,
        port_num: process.env.DB_PORT_NUM,
        database: process.env.DB_DATABASE,
        username: process.env.DB_USERNAME,
        password: process.env.DB_PASSWORD,
    };

    Object.keys(config).forEach(propertyName => {
        const propertyValue = config[propertyName];
        if (typeof propertyValue !== 'string') exitError(`missing heavydb config property ${propertyName}`);
        console.log(`config ${propertyName} = '${propertyValue}'`);
    });

    const connector = new Connector()
    .protocol(config.protocol)
    .host(config.hostname)
    .port(config.port_num)
    .dbName(config.database)
    .user(config.username)
    .password(config.password);

    console.log(`connect to heavydb...`);

    const useCallbackInterface = false;

    if (useCallbackInterface) {
        connector.connect((err, session) => {
            if (err) exitError(err);
            console.log(`connect succeeded!`);
            executeQuery(session);
        });
    }
    else {
        connector.connectAsync()
        .then(session => {
            console.log(`connect succeeded!`);
            executeQuery(session);
        })
        .catch(err => {
            console.log(`connection error:`);
            exitError(err);
        });
    }

    function executeQuery(session) {
        const query = `select count(*) from telemetry_test_alpha;`
        console.log(`send query to heavydb: ${query}`);
        session.query(query, (err, data) => {
            if (err) exitError(err);
            console.log(`${data.toString()}\n`);
        });
    }

    function exitError(err) {
        console.error(err);
        process.exit(1001);
    }

    And here is the shell script heavysql-test:

    #!/bin/bash

    QUERY="select count(*) from telemetry_test_alpha;"

    PROTOCOL=

    echo "DB_PROTOCOL is '$DB_PROTOCOL'"

    if [[ "$DB_PROTOCOL" = "https" || "$DB_PROTOCOL" = "http" ]]; then
      PROTOCOL="--$DB_PROTOCOL"
    fi

    echo "connect with: heavysql $DB_DATABASE $PROTOCOL -s $DB_HOSTNAME --port $DB_PORT_NUM -u $DB_USERNAME -p $DB_PASSWORD"

    echo "$QUERY" | heavysql $DB_DATABASE $PROTOCOL -s $DB_HOSTNAME --port $DB_PORT_NUM -u $DB_USERNAME -p $DB_PASSWORD
    0
    Comment actions Permalink
  • Avatar
    Candido Dessanti

    Hi,

    Is the Node.js program hangs, and you find yourself having to interrupt it?

    (I'm not familiar with Node.js, sorry for the stupid question)

    0
    Comment actions Permalink
  • Avatar
    Lee Jenkins

    Yes, that is true. The NodeJS program hangs when trying to connect and all the supplied connection information is correct. In an attempt to troubleshoot the program, I also tested it with incorrect connection information. If I supply incorrect information, such as the wrong port number for the HeavyDB service, then the NodeJS app immediately reports an error. In this case, the program does not hang.

    FYI The javascript connector for HeavyAI uses a "callback" interface, where HeavyAI is supposed to call the callback function if the connection succeeds *or* fails. But in my tests, HeavyAI only calls the callback when the connection fails.

    Hope that helps.

    0
    Comment actions Permalink
  • Avatar
    Candido Dessanti

    Hi,

    We did noticed that you have specified mapd as protocol; the protocol can be http and https, depending on how you configured your server, and you should use the corresponding HTTP (HTPPS) port (6278) to connect to the server. 

    Regards,
    Candido

    0
    Comment actions Permalink
  • Avatar
    Lee Jenkins

    I have narrowed down the issue. The program was using PROTOCOL=mapd in the connection configuration.

    When running the code your front-end engineer supplied, it would hang if it was configured with PROTOCOL=mapd, but it would connect successfully if it was configured with PROTOCOL=https.

    Next I ran my nodejs program with PROTOCOL=https, and it, too, was able to connect successfully.

    Of course, these protocols answer on different ports, so the configuration change also reflected the correct port numbers.

    Finally, I ran the `heavysql` command with both configurations, mapd and https. The `heavysql` command connected successfully with both protocols.

    My conclusion is that the javascript connector is not working correctly with the mapd protocol.

    Now that I know, I can simply use the https protocol.

    0
    Comment actions Permalink
  • Avatar
    Candido Dessanti

    There isn't a 'mapd' protocol (probably we should review the documentation) . Port 6274 uses a TCP binary protocol, while port 6276, which is a recent addition, utilizes a binary HTTP protocol. Neither of these ports is compatible with the JS connector, but this isn't an issue since the JS connector is designed for web applications.

    Anyway, I'm glad to hear that it's now working for you.

    0
    Comment actions Permalink

Please sign in to leave a comment.