开发者

Locking on an object?

I'm very new to Node.js and I'm sure there's an easy answer to this, I just can't find it :(

I'm using the filesystem to hold 'packages' (folders with a status extensions 'mypackage.idle') Users can perform actions on these which would cause the status to go to something like 'qa', or 'deploying' etc... If the server is accepting lots of requests and multiple requests come in for the same package how would I check the status and then perform an action, which would cha开发者_运维知识库nge the status, guaranteeing that another request didn't alter it before/during the action took place?

so in c# something like this

lock (someLock) { checkStatus(); performAction(); }

Thanks :)


If checkStatus() and performAction() are synchronous functions called one after another, then as others mentioned earlier: their exectution will run uninterupted till completion. However, I suspect that in reality both of these functions are asynchoronous, and the realistic case of composing them is something like:

function checkStatus(callback){
  doSomeIOStuff(function(something){
    callback(something == ok);
  });
}

checkStatus(function(status){
  if(status == true){
    performAction();
  }
});

The above code is subject to race conditions, as when doSomeIOStuff is being perfomed instead of waiting for it new request can be served.

You may want to check https://www.npmjs.com/package/rwlock library.


This is a bit misleading. There are many script languages that are suppose to be single threaded, but when sharing data from the same source this creates a problem. NodeJs might be single threaded when you are running a single request, but when you have multiple requests trying to access the same data, it just behaves as it creates kind of the same problem as if you were running a multithreaded language.

There is already an answer about this here : Locking on an object?

WATCH sentinel_key
GET value_of_interest
if (value_of_interest = FULL)
    MULTI
    SET sentinel_key = foo
    EXEC
    if (EXEC returned 1, i.e. succeeded)
        do_something();
    else
        do_nothing();
else
    UNWATCH


One thing you can do is lock on an external object, for instance, a sequence in a database such as Oracle or Redis.

http://redis.io/commands

For example, I am using cluster with node.js (I have 4 cores) and I have a node.js function and each time I run through it, I increment a variable. I basically need to lock on that variable so no two threads use the same value of that variable.

check this out How to create a distributed lock with Redis?

and this https://engineering.gosquared.com/distributed-locks-using-redis

I think you can run with this idea if you know what you are doing.


If you are making asynchronous calls with callbacks, this means multiple clients could potentially make the same, or related requests, and receive responses in different orders. This is definitely a case where locking is useful. You won't be 'locking a thread' in the traditional sense, but merely ensuring asynchronous calls, and their callbacks are made in a predictable order. The async-lock package looks like it handles this scenario.

https://www.npmjs.com/package/async-lock


warning, node.js change semantic if you add a log entry beucause logging is IO bound.

if you change from

qa_action_performed = false
function handle_request() {
  if (check_status() == STATUS_QA && !qa_action_performed) {
    qa_action_performed = true
    perform_action()
  }
}

to

qa_action_performed = false
function handle_request() {
  if (check_status() == STATUS_QA && !qa_action_performed) {
    console.log("my log stuff");
    qa_action_performed = true
    perform_action()
  }
}

more than one thread can execute perform_action().


You don't have to worry about synchronization with Node.js since it's single threaded with an event loop. This is one of the advantage of the architecture that Node.js use.

Nothing will be executed between checkStatus() and performAction().


There are no locks in node.js -- because you shouldn't need them. There's only one thread (the event loop) and your code is never interrupted unless you perform an asynchronous action like I/O. Hence your code should never block. You can't do any parallel code execution.

That said, your code could look something like this:

qa_action_performed = false
function handle_request() {
  if (check_status() == STATUS_QA && !qa_action_performed) {
    qa_action_performed = true
    perform_action()
  }
}

Between check_status() and perform_action() no other thread can interrupt because there is no I/O. As soon as you enter the if clause and set qa_action_performed = true, no other code will enter the if block and hence perform_action() is never executed twice, even if perform_action() takes time performing I/O.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜