简体   繁体   中英

Node.js - Ensuring a non-blocking call finishes

I'm using the pg postgres node module to interact with my database. The code works without an issue when I use pg 's evented API. Below is an example of the code:

Migration.js

 exports.up = function(logger){
    var pg = require("pg")
        , connectionString = //process.env.CONNECTIONSTRING
        , client = new pg.Client(connectionString);

    client.connect();

    var cmd = "CREATE TABLE users( "
                + "id SERIAL NOT NULL, "
                + "firstName VARCHAR(50) NOT NULL, "
                + "lastName VARCHAR(50) NOT NULL, "
                + "CONSTRAINT pk_userid PRIMARY KEY (id) "
                + ")";

    var query = client.query(cmd);

    query.on("end", function(){
        client.end();
            logger.log("complete");
    });
};

I'm using commander.js to write a command line utility around this migration script; however, the non-blocking call of the pg snippet is freeing up the command line interface script to finish before the database updates have been done. Below is an example commander snippet:

MyCliTool

var program = require('commander');

program
    .version('1.0.2');

program
    .command("up")
    .description("Migrates up")
    .action(function(){
        require("../src/migration").up();
    });

// Additional code removed for brevity

Is there a way that I can change the migration (or the commander.js app) script to ensure that the migration's up() function will finish prior to my cli script finishing? I have tried using callbacks but that appears to not be working.

UPDATE Another example to illustrate this point. Below is a unit test (written with mocha ) concerning the issue.

Up-test.js

describe("feature", function(){
    it("should finish", function(){
        var logger = {};
        var finished = false;
        logger.log = function(){finished = true;};

        var migration = require("../src/migration.js");
        migration.up(logger);
        assert(finished, "function didn't finish"); // finished is false when this gets called.
    });
});

Looks like your original script has a pain point around program.action(function () {}); :

program
    .command("up")
    .description("Migrates up")
    .action(function(){
        require("../src/migration").up();

        // nothing preventing this function from exiting immediately
    });

I poked around a bit in commander.js docs and couldn't find anything regarding supplying a callback to your .action() program. If I were writing it, the code would look something like this:

program
    .command("up")
    .description("Migrates up")
    .action(function (completedCallback) {

        require("../src/migration").up(function () {
            // migration is complete
            completedCallback();
        });

    });

Your postgre-related script looks fine, though. A somewhat unrelated note might be to have require("../src/migration").up(); return an instance of require("events").EventEmitter and emit events you'd like to have visibility into, instead of using a logger variable. But that's just preference.

Try setting timers (http://nodejs.org/api/timers.html). We do this within our Azure CLI tool to have a spinner that runs when you are doing long running operations.

You can drill into the code here to see how we do it: https://github.com/WindowsAzure/azure-sdk-for-node/blob/master/lib/cli/cli.js . Search for the progress() function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM