2016-10-11 01:51:11 +08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var RedisDistlockLocker = require('./provider/redis-distlock');
|
|
|
|
var debug = require('../util/debug')('leader-locker');
|
2016-10-19 02:34:22 +08:00
|
|
|
var EventEmitter = require('events').EventEmitter;
|
|
|
|
var util = require('util');
|
2016-10-11 01:51:11 +08:00
|
|
|
|
2016-10-12 19:11:20 +08:00
|
|
|
var LOCK = {
|
|
|
|
TTL: 5000
|
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
function Locker (locker, ttl) {
|
2016-10-19 02:34:22 +08:00
|
|
|
EventEmitter.call(this);
|
2016-10-11 01:51:11 +08:00
|
|
|
this.locker = locker;
|
2016-10-12 19:11:20 +08:00
|
|
|
this.ttl = (Number.isFinite(ttl) && ttl > 0) ? ttl : LOCK.TTL;
|
|
|
|
this.renewInterval = this.ttl / 5;
|
2016-10-12 18:30:13 +08:00
|
|
|
this.intervalIds = {};
|
2016-10-11 01:51:11 +08:00
|
|
|
}
|
2016-10-19 02:34:22 +08:00
|
|
|
util.inherits(Locker, EventEmitter);
|
2016-10-11 01:51:11 +08:00
|
|
|
|
|
|
|
module.exports = Locker;
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
Locker.prototype.lock = function (resource, callback) {
|
2016-10-12 18:30:13 +08:00
|
|
|
var self = this;
|
2016-10-14 19:10:27 +08:00
|
|
|
debug('Locker.lock(%s, %d)', resource, this.ttl);
|
|
|
|
this.locker.lock(resource, this.ttl, function (err, lock) {
|
2016-10-12 23:01:24 +08:00
|
|
|
if (!err) {
|
2016-10-14 19:10:27 +08:00
|
|
|
self.startRenewal(resource);
|
2016-10-12 23:01:24 +08:00
|
|
|
}
|
2016-10-12 18:30:13 +08:00
|
|
|
return callback(err, lock);
|
|
|
|
});
|
2016-10-11 01:51:11 +08:00
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
Locker.prototype.unlock = function (resource, callback) {
|
2016-10-12 18:30:13 +08:00
|
|
|
var self = this;
|
2016-10-14 19:10:27 +08:00
|
|
|
debug('Locker.unlock(%s)', resource);
|
2019-12-24 01:19:08 +08:00
|
|
|
this.locker.unlock(resource, function (err) {
|
2016-10-14 19:10:27 +08:00
|
|
|
self.stopRenewal(resource);
|
2016-10-12 18:30:13 +08:00
|
|
|
return callback(err);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
Locker.prototype.startRenewal = function (resource) {
|
2016-10-12 18:30:13 +08:00
|
|
|
var self = this;
|
2016-10-14 19:10:27 +08:00
|
|
|
if (!this.intervalIds.hasOwnProperty(resource)) {
|
2019-12-24 01:19:08 +08:00
|
|
|
this.intervalIds[resource] = setInterval(function () {
|
2016-10-14 19:10:27 +08:00
|
|
|
debug('Trying to extend lock resource=%s', resource);
|
2019-12-24 01:19:08 +08:00
|
|
|
self.locker.lock(resource, self.ttl, function (err, _lock) {
|
2016-10-12 18:30:13 +08:00
|
|
|
if (err) {
|
2016-10-19 02:34:22 +08:00
|
|
|
self.emit('error', err, resource);
|
2016-10-14 19:10:27 +08:00
|
|
|
return self.stopRenewal(resource);
|
2016-10-12 18:30:13 +08:00
|
|
|
}
|
|
|
|
if (_lock) {
|
2016-10-14 19:10:27 +08:00
|
|
|
debug('Extended lock resource=%s', resource);
|
2016-10-12 18:30:13 +08:00
|
|
|
}
|
|
|
|
});
|
2016-10-12 19:11:20 +08:00
|
|
|
}, this.renewInterval);
|
2016-10-12 18:30:13 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
Locker.prototype.stopRenewal = function (resource) {
|
2016-10-14 19:10:27 +08:00
|
|
|
if (this.intervalIds.hasOwnProperty(resource)) {
|
|
|
|
clearInterval(this.intervalIds[resource]);
|
|
|
|
delete this.intervalIds[resource];
|
2016-10-12 18:30:13 +08:00
|
|
|
}
|
2016-10-11 01:51:11 +08:00
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
module.exports.create = function createLocker (type, config) {
|
2016-10-11 01:51:11 +08:00
|
|
|
if (type !== 'redis-distlock') {
|
|
|
|
throw new Error('Invalid type Locker type. Valid types are: "redis-distlock"');
|
|
|
|
}
|
2016-10-17 21:02:34 +08:00
|
|
|
var locker = new RedisDistlockLocker(config.pool);
|
2016-10-12 19:11:20 +08:00
|
|
|
return new Locker(locker, config.ttl);
|
2016-10-11 01:51:11 +08:00
|
|
|
};
|