Not sure when to close client connection on Express


#1

So I have a series of endpoints in Express that establish a connection to an Aerospike server, and then close it after they have responded with the appropriate data. Here is an example of an endpoint:

app.get("/api/content/:id",function(req,res){
    aero.client(aeroSec.generateConfig()).connect(function(err, db){
        if(err.code != aero.status.AEROSPIKE_OK)  return res.status(403).send();
        var options = {};
        options.filters = [filter.equal("secindex", req.params.id)];
        var query = db.query("ns","posts",options);
        var data;
        var count = 0;
        var s = query.execute();
        s.on("data",function(rec){
           data = rec;
        });
        s.on("error",function(err){
            data = err;    
        });
        s.on("end",function(){
           db.close();
           if(data == undefined) res.status(404).send("NOTHING FOUND");
           else res.status(200).send(data);
        });   
    });
  });

At a face value, there seems to be nothing wrong with the way this is coded. However, I have noticed that after constantly making this particular request constantly every 10 seconds for 4 hours, I suddenly loose the connection and then I’m further unable to make any sort of request to the Aerospike server, necessitating a server restart. Do you have any idea where to place the client.close() command once I’m done with a query?


#2

Hi 0nix,

db.close should be invoked when the application exits.

The client object - db in this case, maintains the connection pool which is used to communicate with Aerospike Server. And client.close() should be invoked only when all the communication with Aerospike server is completed and the application is about to exit as this leads to clean shutdown of the application. On close, the client closes all the connection and releases any resources associated with it.


#3

So, because this is running on a server that is not meant to shut down, I must not call client.close()? Did I understand you correctly?


#4

Also, in the interest of full disclosure: This is the error I get after an hour or so of normal operation:

ERROR(28134) [connect.cc:69] [Connect] - Connecting to Cluster Failed

#5

The client object maintains the necessary information and it does not run in the server. This information is used to communicate with Aerospike Server. This is information about Aerospike Cluster and it is common for any request you make from your application. Client.close() erases all the contextual information necessary to contact Aerospike Server. This client is part of the application not server.

Is the server running when you see connection failure in the application?

ERROR(28134) [connect.cc:69] [Connect] - Connecting to Cluster Failed - This error can occur when there is no Aerospike server running. The host name you specified for client creation should specify the IP address/host name of Aerospike Server.

Can you also share the following details with us :

  1. Which version of aerospike server are you using ?
  2. Are you running secondary index queries on a non-existing set ?

Thanks


#6

Yes the server is running when I see a connection failure in the application, and before that errors appears I’m able to connect and interface with the aerospike server just fine. I’m currently using version 3.5.15, with client version 1.0.49. All the secondary index queries I’m running have existing sets to match.

I have also been able to fix the problem for the time being, by commenting out all instances of client.close() in my code, not just the one endpoint that is presenting problems.


#7

The problem has not been fixed by simply commenting out client.close() on my endpoints. It has merely delayed it. I decided to install the aerospike database in the same server as I did my node process, but the problem persists.


#8

@0nix,

Looks like on the day of your last comment, you took your question to Stackoverflow here.

I am reposting @gayathri’s answer below for all to see:

"The code snippet shows that application creates as many client objects as number of requests received. The common usage is, a single client object is created and this is shared for all communications to Aerospike server. Another clarification is, client.connect() is a synchronous API call. And there is a sample web application in node.js using express and Aerospike. Here is the link. Please refer here for more clarifications.

The above code can be refactored like this

 var aerospike = require('aerospike');
 var express   = require('express');
 var app       = express();
 var aerospikeConfig = {
      // add a node in the cluster.
      hosts: [{addr: "192.168.0.1", port: 3000 }] 
 }  
 var client = aerospike.client(aerospikeConfig);
 // client.connect() is a synchronous API call.
 client.connect(function(err, client) {
    if(err.code != aerospike.status.AEROSPIKE_OK) {
        // application should exit or re-attempt the connect call.
        // If connect call fails, connection with Aerospike server is
        // is not established. Subsequent aerospike API calls will fail.
        return err; 
    }
 });

app.get("/api/content/:id",function(req,res){
    var options = {};
    options.filters = [filter.equal("secindex", req.params.id)];
    var query = client.query("ns","posts",options);
    var data;
    var count = 0;
    var s = query.execute();
    s.on("data",function(rec){
       data = rec;
    });
    s.on("error",function(err){
        data = err;    
    });
    s.on("end",function(){
       client.close();
       if(data == undefined) res.status(404).send("NOTHING FOUND");
       else res.status(200).send(data);
    });   
});

#9

I’m pretty sure you’re experiencing what’s described in the issue I just opened on github : https://github.com/aerospike/aerospike-client-nodejs/issues/88

As I found, it seems that you should never call the close method of the aerospike node client before the application exits. Otherwise you can expect strange behaviors, the worst one being a segfault.

As explained by @gayathri the close method currently releases some resources allocated by the client itself (and not only the connection).

Calling again the connect method makes the client tries to re-use some released memory and it will end badly.

In my opinion, we should be able to close/connect as much as needed in the same application instance, or at least not having the client segfaulting and printing a log in a safe manner (ie: not using a released pointer) and documenting it on the close method API documentation, since it’s currently just telling us it’s closing the connection while it is completely destroying the client which become useless