@@ -704,6 +704,128 @@ significantly compared to firing the same commands in a loop without waiting for
704
704
the result! See the benchmarks for further comparison. Please remember that all
705
705
commands are kept in memory until they are fired.
706
706
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
+
707
829
## Monitor mode
708
830
709
831
Redis supports the ` MONITOR ` command, which lets you see all commands received
0 commit comments