Skip to content

Instantly share code, notes, and snippets.

@sanchezzzhak
Last active January 15, 2019 08:19
Show Gist options
  • Save sanchezzzhak/9faab7e9cddf17cdec8ad5e9132b0dce to your computer and use it in GitHub Desktop.
Save sanchezzzhak/9faab7e9cddf17cdec8ad5e9132b0dce to your computer and use it in GitHub Desktop.
JS nodejs mongo seve loop
"use strict";
const EventEmitter = require('events').EventEmitter
const mongodb = require('mongodb');
const MONGODB_EVENTS = {
RECONNECT: 'reconnect',
RECONNECT_FAILED: 'reconnectFailed',
LEFT: 'left',
JOINED: 'joined',
FULLSETUP: 'fullsetup',
OPEN: 'open',
CLOSE: 'close',
TIMEOUT: 'timeout',
ERROR: 'error',
};
const STATES = {
disconnected: 0,
connected: 1,
connecting: 2,
disconnecting: 3,
uninitialized: 99
};
const RECOVERABLE_ERROR = [
'ESOCKETTIMEDOUT',
'ETIMEDOUT',
'ECONNRESET',
'ECONNREFUSED'
];
/**
* ```js
* const AppDbConfig {
* uri: 'mongodb://localhost:47017,localhost:37017,localhost:27017/database?replicaSet=rs1',
* dbName: 'test_db',
* options: {}
* };
* let mongodb = new MongoDb( AppDbConfig.uri, AppDbConfig.dbName, AppDbConfig.options);
* mongodb.connect( (err, result) => {
*
* });
* ```
*
* @param url {String} connection uri
* @param dbName {String} database name
* @param options {Object} mongodb options
* @constructor
*/
function MongoDb(url, dbName, options) {
this.url = url;
this.dbName = dbName;
this.options = options;
this.connection = null;
this.readyState = STATES.disconnected;
}
MongoDb.prototype.__proto__ = EventEmitter.prototype;
/**
* @param callback {Function|null}
* @return {MongoDb}
*/
MongoDb.prototype.connect = function (callback) {
let self = this;
const promise = new Promise((resolve, reject) => {
let client = new mongodb.MongoClient(self.url, self.options);
self.client = client;
client.connect(function (error) {
if (error) {
self.readyState = STATES.disconnected;
return reject(error);
}
const db = client.db(self.dbName);
self.db = db;
db.on(MONGODB_EVENTS.RECONNECT, function () {
self.readyState = STATES.connected;
self.emit(MONGODB_EVENTS.RECONNECT);
});
db.s.topology.on(MONGODB_EVENTS.RECONNECT_FAILED, function () {
self.emit(MONGODB_EVENTS.RECONNECT_FAILED);
});
db.s.topology.on(MONGODB_EVENTS.LEFT, function (data) {
self.emit(MONGODB_EVENTS.LEFT, data);
});
db.s.topology.on(MONGODB_EVENTS.JOINED, function (data) {
self.emit(MONGODB_EVENTS.JOINED, data);
});
db.s.topology.on(MONGODB_EVENTS.FULLSETUP, function (data) {
self.emit(MONGODB_EVENTS.FULLSETUP, data);
});
db.on(MONGODB_EVENTS.CLOSE, function () {
self.readyState = STATES.disconnected;
self.emit(MONGODB_EVENTS.CLOSE);
});
db.on(MONGODB_EVENTS.TIMEOUT, function () {
self.emit(MONGODB_EVENTS.TIMEOUT);
});
delete self.then;
delete self.catch;
self.readyState = STATES.connected;
resolve(self);
self.emit(MONGODB_EVENTS.OPEN);
});
});
this.$initialConnection = Promise.all([promise, parsePromise]).then(res => res[0]).catch(err => {
if (this.listeners(MONGODB_EVENTS.ERROR).length > 0) {
process.nextTick(() => this.emit(MONGODB_EVENTS.ERROR, err));
return;
}
throw err;
});
this.then = function (resolve, reject) {
return this.$initialConnection.then(resolve, reject);
};
this.catch = function (reject) {
return this.$initialConnection.catch(reject);
};
if (callback !== undefined && callback !== null) {
this.$initialConnection.then( () => callback(null, this), err => callback(err));
}
return this;
};
/**
* @param collectionName {String}
* @param data {Object} save record data
* @param callback {Function}
* @param attemptsLeft {Number}
* @param retryDelay {Number}
* @param lastError {Error|null}
* @return {*}
*/
MongoDb.prototype.save = function (collectionName, data, callback, attemptsLeft = 1, retryDelay = 0, lastError = null) {
let self = this;
if (attemptsLeft <= 0) {
return callback((lastError !== null ? lastError : new Error('mongodb::save - attempts limit end')));
}
else if (self.readyState === STATES.connected) {
self.db.collection(collectionName).save(data, function (err, result) {
let e = null;
if (err) {
e = new Error('mongodb::save error');
e.code = err.code;
if(err && RECOVERABLE_ERROR.indexOf(err.code) > -1){
setTimeout((function () {
self.save(collectionName, data, callback, --attemptsLeft, retryDelay, e);
}), retryDelay);
}
return;
}
return callback(err, result);
});
} else {
return callback(new Error('mongodb::save - not connected'));
}
};
module.exports = MongoDb;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment