简体   繁体   中英

Promises in while(true) loop / waiting for promise to resolve

I want to write a small worker app in node.js.
This app would read from AWS-SQS, process the data in some way, and spit it out to another AWS-SQS.
So far I have written:

while(true){
    readFromQueue()
    .then(transform)
    .then(writeToQueue);
}

function transform(data) {
    console.log("> transforming...");
    //transformation logic
    return data;
}

//TODO: need to remove message from queue after read!
function readFromQueue() {
    // var params = {
    //   QueueUrl: 'STRING_VALUE',
    //   WaitTimeSeconds: 2
    // };

    // return new Promise(function(resolve, reject) {
    //  sqs.receiveMessage(params, function(err, data) {
    //      if (err) reject(err);
    //      else     resolve(data);
    //  });
    // });
    return new Promise(function(resolve, reject) {
        console.log("> reading from queue...");
        resolve({ data : "world" });
    });
}

function writeToQueue(data) {
    // var params = {
    //  MessageBody: data,
    //  QueueUrl: 'STRING_VALUE',
    // };
    // sqs.sendMessage(params, function(err, data) {
    //  if (err) console.log(err, err.stack);
    //  else     console.log(data);
    // });
    console.log("> writing to queue...");
    console.log(">> " + data);
}

As you can see everything is set up for AWS, but when I run it locally for the time being, I would just have some mock stuff inside, until I actually get my transformation logic tested etc...
The problems I have are:

  • AWS-SQS API is async, it takes a callback. I wrapped it with a promise because I prefer promises to callbacks. Nevertheless, I wonder if I should block it and make it sync rather than async (for the reason below, but might be unrelated).
  • When I run this, I can see only "reading from queue.." output, it's almost as if "transform" and "writeToQueue" are not executed...
  • If I, however, comment out the while loop (so the script runs only once), I can see output from all 3 steps.

So am I doing something wrong? I can understand that since promises are async, my while loop will go crazy and create thousands of them, so that concerns me... Nevertheless I want to initiate another loop once the previous read->transform->write has been finished. Is there some other pattern I should use here? Or just block and wait for readFromQueue to end...

--EDIT--
It does execute everything if not wrapped in while(true):

readFromQueue()
        .then(transform)
        .then(writeToQueue);

I also understand that since while(true) is being executed, it will essentially block the thread, and therefore the promise is not resolved. So is there a way around it?

I am falling back to my setInterval way. I know you said that reading queue has to start immediately after the writing is finished, but 10ms isn't much of delay if you ask me.

function someFunc(){
    if(readingQueue)    return;
    readingQueue = true;
    return readFromQueue()
      .then(transform)
      .then(writeToQueue)
      .catch(someErrorHandler)
      .then(function(){
        readingQueue=false;
      })
} 

var readingQueue = false;
setInterval(someFunc, 10);

After evaluating all answers in here , I tried deasync , which did the job just fine :)
Nevertheless, I decided to go with mido22 answer above, just because I didn't want a plugin that is fiddling with node's event-loop.

Instead of this:

while(true){
    readFromQueue()
    .then(transform)
    .then(writeToQueue);
}

Can't you use a recursive function? Something like this:

function getData(){
    return readFromQueue()
        .then(transform)
        .then(function(data){
            writeToQueue(data);
            getData();
        });
}

getData(); //Just to get it starting.

I also ran into a similar issue (see setTimeout issue trying to wait for execution of async ).

I've learned the lesson of sync patterns to be avoided in javascript and so i think your code could be rewritten with something similar:

function queueLooping(loopExitConditionPromise) {

    var blockingGuard = { done: false };

    loopExitConditionPromise.then(function () {
        blockingGuard.done = true;
    });

    return loopingSequence;

    var loopingSequence = function() {
        readFromQueue()
            .then(transform)
            .then(writeToQueue);
        if(!blockingGuard.done) 
            loopingSequence();
        else
            return;
    };

    var readFromQueue = function () {
        console.log("> reading from queue...");
        // ...
    }

    var transform = function (data) {
        console.log("> transforming...");
        // ...
    }

    var writeToQueue = function (data) {
        console.log("> writing to queue...");
        // ...
    }
}

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