0

I was trying to implement an event loop. The purpose of the loop is simple:

  1. If, the queue is not empty, let task be the oldest entry in the queue.
  2. Process task
  3. If, task generates a return value, cache it.
  4. Check the queue for task.
  5. If, the queue is not empty, adopt the next task as the current task context.
  6. Pass the cached return value to the new task.

I tried an implementation in Nodejs in the following manner:

function task(){
this.task = Array.prototype.shift.call(arguments);
this.state = 'unprocessed';
this.successCallback = null;
this.failureCallback = null;
}
task.prototype.afterThat = function(){
if(arguments.length > 1){
this.successCallback = Array.prototype.shift.call(arguments);
this.failureCallback = Array.prototype.shift.call(arguments);
}
}
task.prototype._loop = function(){
let ctx = this;
while(ctx.state === 'unprocessed'){ // Source of problem
    setImmediate(this.task, function(){
    // change ctx.state if needed
   }, function(){
   // change ctx.state to 'processed'
   });
 }
}

The differences between this implementation and that of an event loop are as follows:

  1. Rather than maintaining an array of task, the successCallback can instantiate a new task as its return which, is then adopted as the current task.
  2. Based on the processing, the task state must change (or not, if, a new pending task is adopted which, has its state as 'unprocessed').

I believe the problem is the setImmediate invocation which, cannot change the context state because, the current execution state never terminates and keeps adding a new call for the same task in the event queue.

I hope I have explained it well and would appreciate some guidelines for implementation and, any errors that I may have in my understanding of the event queue.

Thanks.

Abrar Hossain
  • 2,594
  • 8
  • 29
  • 54
  • 1
    I'd suggest indenting your code better. I believe you're defining `task.prototype._loop` inside of `task.prototype.afterThat`. – Mike Cluck Jun 16 '17 at 16:11
  • 1
    Your `while` loop is an infinite loop. JS is single threaded and thus nothing else can run because of your `while` loop. You need to check `ctx.state` after you complete running a task. `setImmediate()` is not blocking. It does not run until your `while` loop is done which is an infinite loop so it's never done. – jfriend00 Jun 16 '17 at 16:14

1 Answers1

2

Your while loop is an infinite loop. JS is single threaded and thus nothing else can run until your while loop finishes. Because nothing else can run, ctx.state will never change. Because ctx.state can never change, your while loop runs forever.

Each time the loop runs it calls setImmediate() which schedules a task to run, but that task can't actually run until the while loop finishes. Thus you're deadlocked and you will be piling up a massive list of tasks to run (eventually overflowing some system resource probably).

You need to check ctx.state after you complete running a task (probably in the success and failure callbacks), not in a loop like this.

setImmediate() is not blocking. The function you schedule with setImmediate() does not run until your while loop is done, but that while loop never finds its condition so it never stops because nothing else can run until the while loop is done.

Instead, call the next task and when that is complete, then check ctx.state. Since you don't show or describe how this is used or what you're really trying to accomplish, I'm unsure the best implementation to suggest. If you want more help with that, then you need to show us a lot more about what you're trying to accomplish and how you want to use this class.

My guess is that you could use promises to accomplish what you're trying to do without having to write much infrastructure code yourself at all since promises are very good tools for sequencing asynchronous tasks.


FYI, there are several things wrong with your code, such as missing closing braces and parens. What you have posted will not even parse correctly, much less run. And, please indent code properly when posting.


jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • i will take a note of that. thanks for your suggestion. – Abrar Hossain Jun 16 '17 at 18:43
  • @AbrarHossain - If this answered your question or led you to an answer, then you can indicate that to the community by clicking the green checkmark next to the answer that helped you the most. This will also earn you some reputation points on stack overflow for following the proper procedure. – jfriend00 Jun 23 '17 at 23:37
  • thanks so much for your effort. I just have one more question. If I want to add a mutex to this code, like block the ctx object before checking the state, would that help. Pardon if I terminology is somewhat off – Abrar Hossain Jun 23 '17 at 23:57
  • @AbrarHossain - Javascript in node.js is single threaded and thus has no need for a mutex and does not have such a thing. If you are trying to manage some state across asynchronous operations, you can just use your own Javascript state variables. Since nodejs Javascript is single threaded, there is no problem just using regular variables. No need for a mutex. And, you can't "block the ctx object before checking state" in Javascript. No such thing and no need for trying to do so. – jfriend00 Jun 24 '17 at 00:01