To implement optimistic locking (Check-and-Set) using the WATCH command, you must use a Redis object that shares the same connection as your Transaction object. This is achieved via tx.redis().
Because WATCH relies on the connection state, you cannot get results from commands inside a transaction until .exec() is called. Using the Redis object returned by tx.redis() allows you to send WATCH and GET commands and receive immediate results within the same connection.
If a WatchError is caught, it means the watched key was modified by another client, and you should retry the transaction loop.
auto redis = Redis("tcp://127.0.0.1");
auto tx = redis.transaction();
auto r = tx.redis(); // Shares connection with tx
while (true) {
try {
r.watch("key");
auto val = r.get("key");
auto num = val ? std::stoi(*val) : 0;
++num;
auto replies = tx.set("key", std::to_string(num)).exec();
assert(replies.size() == 1 && replies.get<bool>(0) == true);
break;
} catch (const WatchError &err) {
continue; // Retry
} catch (const Error &err) {
throw; // Transaction is invalid
}
}