Skip to content
Merged
1 change: 1 addition & 0 deletions configs/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
LOG_ERRORS=true
TOKEN_EXPIRES="1 year"
REDIS_KEY_EXPIRES="5 minutes"
REDIS_LOCK_EXPIRES="6 minutes"
DOCK_PROJECT_LIMIT=100000000
DEPLOY_COMMAND="echo DEPLOY"
COOKIE_SECRET="\$up3r,$3<r3t"
Expand Down
10 changes: 7 additions & 3 deletions lib/models/redis/mutex.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ function RedisMutex (key) {
}

RedisMutex.prototype.lock = function (cb) {
this.redis.setnx(this.key, 'lock', function (err, success) {
cb(err, success === '1');
// SET resource-name anystring NX EX max-lock-time
// Is a simple way to implement a locking system with Redis.
// See http://redis.io/commands/set
var expires = process.env.REDIS_LOCK_EXPIRES;
this.redis.set(this.key, 'lock', 'NX', 'PX', expires, function (err, success) {
cb(err, success === 'OK');
});
};

RedisMutex.prototype.unlock = function (cb) {
this.redis.del(this.key, cb);
};
};
93 changes: 93 additions & 0 deletions unit/redis-mutex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
var Lab = require('lab');
var describe = Lab.experiment;
var it = Lab.test;
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var createCount = require('callback-count');
var redisCleaner = require('../test/fixtures/redis-cleaner');
var RedisMutex = require('models/redis/mutex');


describe('RedisMutex', function () {
before(redisCleaner.clean('*'));
after(redisCleaner.clean('*'));

var ctx = {};

describe('lock', function () {

it('should lock', function (done) {
var mutex = new RedisMutex('key-1');
mutex.lock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal(true);
done();
});
});

it('should fail to lock with the same key', function (done) {
var mutex = new RedisMutex('key-1');
mutex.lock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal(false);
done();
});
});

describe('unlock', function () {

it('should be able to lock after unlock', function (done) {
var mutex = new RedisMutex('key-1');
mutex.unlock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal('1');
mutex.lock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal(true);
done();
});
});
});

});


describe('ttl', function () {
before(function (done) {
ctx.originREDIS_LOCK_EXPIRES = process.env.REDIS_LOCK_EXPIRES;
done();
});
after(function (done) {
process.env.REDIS_LOCK_EXPIRES = ctx.originREDIS_LOCK_EXPIRES;
done();
});

it('should release lock after expiration time', function (done) {
var count = createCount(2, done);
process.env.REDIS_LOCK_EXPIRES = 50;
var mutex1 = new RedisMutex('new-key-1');
var mutex2 = new RedisMutex('new-key-1');
setTimeout(function () {
mutex2.lock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal(true);
count.next();
});
}, 100);
mutex1.lock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal(true);
mutex2.lock(function (err, success) {
if (err) { return done(err); }
expect(success).to.equal(false);
count.next();
});
});
});
});

});


});