You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-09 00:22:08 +03:00
Added documentation for REDIS optimistic lock system.
This commit is contained in:
93
README.md
93
README.md
@@ -704,6 +704,99 @@ significantly compared to firing the same commands in a loop without waiting for
|
||||
the result! See the benchmarks for further comparison. Please remember that all
|
||||
commands are kept in memory until they are fired.
|
||||
|
||||
## Optimistic Locks
|
||||
|
||||
Using `multi` you can make sure your modifications run as a transaction, but you
|
||||
can't be sure you got there first. What if another client modified a key while
|
||||
you were working with it's data?
|
||||
|
||||
To solve this, Redis supports the [WATCH](https://redis.io/topics/transactions)
|
||||
command, which is meant to be used with MULTI:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
client.watch("foo", function( err ){
|
||||
if(err) throw err;
|
||||
|
||||
client.get("foo", function(err, result) {
|
||||
if(err) throw err;
|
||||
|
||||
// Process result
|
||||
// Heavy and time consuming operation here
|
||||
|
||||
client.multi()
|
||||
.set("foo", "some heavy computation")
|
||||
.exec(function(err, results) {
|
||||
|
||||
/**
|
||||
* If err is null, it means Redis successfully attempted
|
||||
* the operation.
|
||||
*/
|
||||
if(err) throw err;
|
||||
|
||||
/**
|
||||
* If results === null, it means that a concurrent client
|
||||
* changed the key while we were processing it and thus
|
||||
* the execution of the MULTI command was not performed.
|
||||
*
|
||||
* NOTICE: Failing an execution of MULTI is not considered
|
||||
* an error. So you will have err === null and results === null
|
||||
*/
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The above snippet shows the correct usage of `watch` with `multi`. Every time a
|
||||
watched key is changed before the execution of a `multi` command, the execution
|
||||
will return `null`. On a normal situation, the execution will return an array of
|
||||
values with the results of the operations.
|
||||
|
||||
As stated in the snippet, failing the execution of a `multi` command being watched
|
||||
is not considered an error. The execution may return an error if, for example, the
|
||||
client cannot connect to Redis.
|
||||
|
||||
An example where we can see the execution of a `multi` command fail is as follows:
|
||||
|
||||
```js
|
||||
let clients = {};
|
||||
clients.watcher = redis.createClient({ ... } );
|
||||
clients.alterer = clients.watcher.duplicate();
|
||||
|
||||
clients.watcher.watch('foo',function(err) {
|
||||
if (err) { throw err; }
|
||||
//if you comment out the next line, the transaction will work
|
||||
clients.alterer.set('foo',Math.random(), (err) => {if (err) { throw err; }})
|
||||
|
||||
//using a setTimeout here to ensure that the MULTI/EXEC will come after the SET.
|
||||
//Normally, you would use a callback to ensure order, but I want the above SET command
|
||||
//to be easily comment-out-able.
|
||||
setTimeout(function() {
|
||||
clients.watcher
|
||||
.multi()
|
||||
.set('foo','abc')
|
||||
.set('bar','1234')
|
||||
.exec((err,results) => {
|
||||
if (err) { throw err; }
|
||||
if (results === null) {
|
||||
console.log('transaction aborted because results were null');
|
||||
} else {
|
||||
console.log('transaction worked and returned',results)
|
||||
}
|
||||
clients.watcher.quit();
|
||||
clients.alterer.quit();
|
||||
});
|
||||
},1000);
|
||||
});
|
||||
```
|
||||
|
||||
**NOTE**: Redis WATCH does not work on fields of hashes and other objects. You can watch a hash
|
||||
to see if anything inside it was modified, but you cannot watch a specific hash field for a
|
||||
modification.
|
||||
|
||||
## Monitor mode
|
||||
|
||||
Redis supports the `MONITOR` command, which lets you see all commands received
|
||||
|
Reference in New Issue
Block a user