Reputation: 512
I'm trying to debug some WatchErrors
in my project and am noticing that we aren't using an isolatedClient
and am wondering if that is the cause. I don't see any logs (or code paths) that would indicate that the watched keys are being changed after being watched.
Here is basically what my code looks like when I actually write to Redis in a transaction:
try {
await this.client.watch(key);
await this.client
.multi()
.hSet(key, some_value)
.expire(key, some_expiration)
.exec();
}
catch (e) {
if (e instanceof WatchError) {
// seeing this block get hit often
}
throw e;
}
I noticed in the node-redis README that the Transactions section gives an example without calling .watch()
without creating an isolatedClient
. However, in the linked example that does call .watch()
, there is the additional creation of an isolatedClient
with the executeIsolated
method.
What exactly are the implications of using an isolatedClient
? Do we need to use one of these if we are calling .watch()
and if so, why? Will a WatchError
be thrown if a different connection is used between .watch()
and .exec()
?
Upvotes: 0
Views: 343
Reputation: 3194
redis-server
stores the WATCH
state on the connection, which means that concurrent WATCH
and MULTI
/EXEC
will override the state for each other... in this scenario you'll need to have a pool of connections, and every time you need to WATCH
, take a connection from the pool, and use it instead (which is exactly what executeIsolated
is doing):
client.executeIsolated(async isolatedClient => {
await isolatedClient.watch(key);
await isolatedClient
.multi()
.hSet(key, some_value)
.expire(key, some_expiration)
.exec();
});
you can configure the pool behavior by passing the isolationPoolOptions
option to createClient
:
createClient({
isolationPoolOptions: {
min: 1,
max: 100
}
});
see generic-pool for more options.
Upvotes: 1