Skip to content

Commit

Permalink
Use evalsha for scripts
Browse files Browse the repository at this point in the history
1. When constructor is called - execute a load scripts to all servers
2. Once we need to execute a script check if it’s loaded - if so do - evalsha otherwise fallback to eval
  • Loading branch information
yosiat committed Jul 13, 2020
1 parent e90e80a commit 28ac160
Showing 1 changed file with 51 additions and 18 deletions.
69 changes: 51 additions & 18 deletions redlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ function Redlock(clients, options) {
this.servers = clients;
if(this.servers.length === 0)
throw new Error('Redlock must be instantiated with at least one redis server.');

this._loadScripts();
}

// Inherit all the EventEmitter methods, like `on`, and `off`
Expand All @@ -142,6 +144,49 @@ util.inherits(Redlock, EventEmitter);
// to destinguish between error types.
Redlock.LockError = LockError;

Redlock.prototype._loadScripts = function () {
this.serverScripts = {};

const loadScriptsPromises = this.servers.map(
(server) => Promise.all([
this._loadScript(server, this.lockScript),
this._loadScript(server, this.unlockScript),
this._loadScript(server, this.extendScript),
])
.then(scripts => {
this.serverScripts[server] = {
lockScript: scripts[0],
unlockScript: scripts[1],
extendScript: scripts[2]
};
}));

return Promise.all(loadScriptsPromises);
}

Redlock.prototype._loadScript = function(server, script) {
return new Promise((resolve, reject) => {
server.script('load', script, (err, result) => {
if(err !== null) {
reject(err);
} else {
resolve(result);
}
})
});
}

Redlock.prototype._executeScript = function(server, name, args, callback) {
if(this.serverScripts[server]) {
const scriptSha = this.serverScripts[server][name];
return server.evalsha(scriptSha, args, callback);

} else {
args.unshift(this[name]);
return server.eval(args, callback);
}
}


// quit
// ----
Expand Down Expand Up @@ -232,15 +277,11 @@ Redlock.prototype.unlock = function unlock(lock, callback) {

// release the lock on each server
self.servers.forEach(function(server){
return server.eval(
[
self.unlockScript,
return self._executeScript(server, 'unlockScript', [
resource.length,
...resource,
lock.value
],
loop
)
], loop);
});

function loop(err, response) {
Expand Down Expand Up @@ -341,32 +382,24 @@ Redlock.prototype._lock = function _lock(resource, value, ttl, callback) {
if(value === null) {
value = self._random();
request = function(server, loop){
return server.eval(
[
self.lockScript,
return self._executeScript(server, 'lockScript', [
resource.length,
...resource,
value,
ttl
],
loop
);
], loop);
};
}

// extend an existing lock
else {
request = function(server, loop){
return server.eval(
[
self.extendScript,
return self._executeScript(server, 'extendScript', [
resource.length,
...resource,
value,
ttl
],
loop
);
], loop);
};
}

Expand Down

0 comments on commit 28ac160

Please sign in to comment.