zamza
Version:
Apache Kafka discovery, indexing, searches, storage, hooks and HTTP gateway
127 lines (126 loc) • 3.95 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Debug = require("debug");
const debug = Debug("zamza:model:lockmodel");
const uuid = require("uuid");
const moment = require("moment");
class LockModel {
constructor(zamza) {
this.metrics = zamza.metrics;
this.name = "lock";
this.model = null;
this.instanceId = uuid.v4();
debug("Generated instance id", this.instanceId);
}
registerModel(mongoose, schemaConstructor) {
const schemaDefinition = {
name: String,
instanceId: String,
timestamp: Number,
};
const schema = new schemaConstructor(schemaDefinition);
// single index
schema.index({ name: 1 }, { unique: true });
// compound index
schema.index({ name: 1, timestamp: 1 }, { unique: false });
schema.index({ name: 1, timestamp: 1, instanceId: 1 }, { unique: false });
this.model = mongoose.model(this.name, schema);
this.model.on("index", (error) => {
if (error) {
debug("Index creation failed", error.message);
}
else {
debug("Index creation successfull.");
}
});
debug("Registered model with schema.");
}
async getLock(name, timeout = 25000) {
let lock;
try {
lock = await this.model.findOneAndUpdate({
name,
timestamp: { $lte: moment().valueOf() },
}, {
instanceId: this.instanceId,
timestamp: moment().valueOf() + timeout,
}, {
upsert: true,
new: true,
});
}
catch (error) {
// duplicated key, happens when multiple clients access resource at the same time
if (error.code === 11000) {
this.metrics.inc("mongo_lock_miss");
return false;
}
// other error
throw error;
}
if (lock && lock.instanceId === this.instanceId) {
this.metrics.inc("mongo_lock_hit");
return true;
}
else {
this.metrics.inc("mongo_lock_miss");
return false;
}
}
async extendLock(name, extendFor = 25000) {
let lock;
try {
lock = await this.model.findOneAndUpdate({
name,
timestamp: { $gte: moment().valueOf() },
instanceId: this.instanceId,
}, {
$inc: {
timestamp: extendFor,
},
}, {
new: true,
});
}
catch (error) {
// duplicated key, happens when multiple clients access resource at the same time
if (error.code === 11000) {
this.metrics.inc("mongo_lock_extend_miss");
return false;
}
// other error
throw error;
}
if (lock) {
this.metrics.inc("mongo_lock_extend_hit");
return true;
}
else {
this.metrics.inc("mongo_lock_extend_miss");
return false;
}
}
async removeLock(name) {
const { n } = await this.model.deleteOne({
name,
instanceId: this.instanceId,
timestamp: { $gte: moment().valueOf() },
});
if (n === 1) {
this.metrics.inc("mongo_lock_removed");
return true;
}
else {
this.metrics.inc("mongo_lock_remove_failed");
return false;
}
}
delete(name) {
return this.model.deleteMany({ name }).exec();
}
truncateCollection() {
debug("Truncating collection");
return this.model.deleteMany({}).exec();
}
}
exports.LockModel = LockModel;