@@ -704,6 +704,99 @@ 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
+ ** NOTE** : Redis WATCH does not work on fields of hashes and other objects. You can watch a hash
797
+ to see if anything inside it was modified, but you cannot watch a specific hash field for a
798
+ modification.
799
+
707
800
## Monitor mode
708
801
709
802
Redis supports the ` MONITOR ` command, which lets you see all commands received
0 commit comments