@@ -704,6 +704,128 @@ significantly compared to firing the same commands in a loop without waiting for
704704the result! See the benchmarks for further comparison. Please remember that all
705705commands are kept in memory until they are fired.
706706
707+ ## Optimistic Locks
708+
709+ Using ` multi ` you can make sure your modifications run as a transaction, but you
710+ can't be sure you got there first. What if another client modified a key while
711+ you were working with it's data?
712+
713+ To solve this, Redis supports the [ WATCH] ( https://redis.io/topics/transactions )
714+ command, which is meant to be used with MULTI:
715+
716+ ``` js
717+ var redis = require (" redis" ),
718+ client = redis .createClient ({ ... });
719+
720+ client .watch (" foo" , function ( err ){
721+ if (err) throw err;
722+
723+ client .get (" foo" , function (err , result ) {
724+ if (err) throw err;
725+
726+ // Process result
727+ // Heavy and time consuming operation here
728+
729+ client .multi ()
730+ .set (" foo" , " some heavy computation" )
731+ .exec (function (err , results ) {
732+
733+ /**
734+ * If err is null, it means Redis successfully attempted
735+ * the operation.
736+ */
737+ if (err) throw err;
738+
739+ /**
740+ * If results === null, it means that a concurrent client
741+ * changed the key while we were processing it and thus
742+ * the execution of the MULTI command was not performed.
743+ *
744+ * NOTICE: Failing an execution of MULTI is not considered
745+ * an error. So you will have err === null and results === null
746+ */
747+
748+ });
749+ });
750+ });
751+ ```
752+
753+ The above snippet shows the correct usage of ` watch ` with ` multi ` . Every time a
754+ watched key is changed before the execution of a ` multi ` command, the execution
755+ will return ` null ` . On a normal situation, the execution will return an array of
756+ values with the results of the operations.
757+
758+ As stated in the snippet, failing the execution of a ` multi ` command being watched
759+ is not considered an error. The execution may return an error if, for example, the
760+ client cannot connect to Redis.
761+
762+ An example where we can see the execution of a ` multi ` command fail is as follows:
763+
764+ ``` js
765+ let clients = {};
766+ clients .watcher = redis .createClient ({ ... } );
767+ clients .alterer = clients .watcher .duplicate ();
768+
769+ clients .watcher .watch (' foo' ,function (err ) {
770+ if (err) { throw err; }
771+ // if you comment out the next line, the transaction will work
772+ clients .alterer .set (' foo' ,Math .random (), (err ) => {if (err) { throw err; }})
773+
774+ // using a setTimeout here to ensure that the MULTI/EXEC will come after the SET.
775+ // Normally, you would use a callback to ensure order, but I want the above SET command
776+ // to be easily comment-out-able.
777+ setTimeout (function () {
778+ clients .watcher
779+ .multi ()
780+ .set (' foo' ,' abc' )
781+ .set (' bar' ,' 1234' )
782+ .exec ((err ,results ) => {
783+ if (err) { throw err; }
784+ if (results === null ) {
785+ console .log (' transaction aborted because results were null' );
786+ } else {
787+ console .log (' transaction worked and returned' ,results)
788+ }
789+ clients .watcher .quit ();
790+ clients .alterer .quit ();
791+ });
792+ },1000 );
793+ });
794+ ```
795+
796+ ### WATCH limitations
797+
798+ Redis WATCH works only on * whole* key values. For example, with WATCH you can
799+ watch a hash for modifications, but you cannot watch a specific field of a hash.
800+
801+ The following example would watch the keys ` foo ` and ` hello ` , not the field ` hello `
802+ of hash ` foo ` :
803+
804+ ``` js
805+ var redis = require (" redis" ),
806+ client = redis .createClient ({ ... });
807+
808+ client .hget ( " foo" , " hello" , function (err , result ){
809+
810+ // Do some processing with the value from this field and watch it after
811+
812+ client .watch (" foo" , " hello" , function ( err ){
813+ if (err) throw err;
814+
815+ /**
816+ * WRONG: This is now watching the keys 'foo' and 'hello'. It is not
817+ * watching the field 'hello' of hash 'foo'. Because the key 'foo'
818+ * refers to a hash, this command is now watching the entire hash
819+ * for modifications.
820+ */
821+ });
822+ } )
823+
824+ ```
825+
826+ This limitation also applies to sets ( cannot watch individual set members )
827+ and any other collections.
828+
707829## Monitor mode
708830
709831Redis supports the ` MONITOR ` command, which lets you see all commands received
0 commit comments