Ini untuk membantu orang lain yang mungkin menemukan diri mereka dalam situasi yang sama seperti yang saya lakukan. Mudah-mudahan bisa distandarisasi. Saya tidak berpikir kita harus menemukan kembali roda setiap kali seseorang perlu membuat aplikasi multi-penyewa.
Contoh ini menjelaskan struktur multi-penyewa dengan setiap klien memiliki database sendiri. Seperti yang saya katakan mungkin ada cara yang lebih baik untuk melakukan ini, tetapi karena saya sendiri tidak mendapatkan bantuan, ini adalah solusi saya.
Jadi, inilah tujuan yang ditargetkan oleh solusi ini:
- setiap klien diidentifikasi oleh subdomain misalnya client1.application.com,
- aplikasi memeriksa apakah subdomain valid,
- aplikasi mencari dan memperoleh informasi koneksi (url database, kredensial, dll) dari database master,
- aplikasi terhubung ke database klien (cukup banyak diserahkan ke klien),
- aplikasi mengambil langkah-langkah untuk memastikan integritas dan manajemen sumber daya (misalnya menggunakan koneksi database yang sama untuk anggota klien yang sama, daripada membuat koneksi baru).
Ini kodenya
di app.js
. Anda berkas
app.use(clientListener()); // checks and identify valid clients
app.use(setclientdb());// sets db for valid clients
Saya telah membuat dua middleware :
clientListener
- untuk mengidentifikasi koneksi klien,setclientdb
- mendapatkan detail klien dari database Master, setelah klien diidentifikasi, dan kemudian membuat koneksi ke database klien.
perangkat tengah clientListener
Saya memeriksa siapa kliennya dengan memeriksa subdomain dari objek permintaan. Saya melakukan banyak pemeriksaan untuk memastikan klien valid (saya tahu kodenya berantakan, dan dapat dibuat lebih bersih). Setelah memastikan klien valid, saya menyimpan info klien dalam sesi. Saya juga memeriksa bahwa jika info klien sudah disimpan dalam sesi, tidak perlu menanyakan database lagi. Kami hanya perlu memastikan bahwa subdomain permintaan, cocok dengan yang sudah disimpan di sesi.
var Clients = require('../models/clients');
var basedomain = dbConfig.baseDomain;
var allowedSubs = {'admin':true, 'www':true };
allowedSubs[basedomain] = true;
function clientlistener() {
return function(req, res, next) {
//console.dir('look at my sub domain ' + req.subdomains[0]);
// console.log(req.session.Client.name);
if( req.subdomains[0] in allowedSubs || typeof req.subdomains[0] === 'undefined' || req.session.Client && req.session.Client.name === req.subdomains[0] ){
//console.dir('look at the sub domain ' + req.subdomains[0]);
//console.dir('testing Session ' + req.session.Client);
console.log('did not search database for '+ req.subdomains[0]);
//console.log(JSON.stringify(req.session.Client, null, 4));
next();
}
else{
Clients.findOne({subdomain: req.subdomains[0]}, function (err, client) {
if(!err){
if(!client){
//res.send(client);
res.send(403, 'Sorry! you cant see that.');
}
else{
console.log('searched database for '+ req.subdomains[0]);
//console.log(JSON.stringify(client, null, 4));
//console.log(client);
// req.session.tester = "moyo cow";
req.session.Client = client;
return next();
}
}
else{
console.log(err);
return next(err)
}
});
}
}
}
module.exports = clientlistener;
setclientdb middleware:
Saya memeriksa semuanya lagi untuk memastikan bahwa klien itu valid. Kemudian koneksi ke database klien dengan info yang diambil dari sesi dibuka.
Saya juga memastikan untuk menyimpan semua koneksi aktif ke dalam objek global, untuk mencegah koneksi baru ke database pada setiap permintaan (kami tidak ingin membebani server mongodb setiap klien dengan koneksi).
var mongoose = require('mongoose');
//var dynamicConnection = require('../models/dynamicMongoose');
function setclientdb() {
return function(req, res, next){
//check if client has an existing db connection /*** Check if client db is connected and pooled *****/
if(/*typeof global.App.clientdbconn === 'undefined' && */ typeof(req.session.Client) !== 'undefined' && global.App.clients[req.session.Client.name] !== req.subdomains[0])
{
//check if client session, matches current client if it matches, establish new connection for client
if(req.session.Client && req.session.Client.name === req.subdomains[0] )
{
console.log('setting db for client ' + req.subdomains[0]+ ' and '+ req.session.Client.dbUrl);
client = mongoose.createConnection(req.session.Client.dbUrl /*, dbconfigoptions*/);
client.on('connected', function () {
console.log('Mongoose default connection open to ' + req.session.Client.name);
});
// When the connection is disconnected
client.on('disconnected', function () {
console.log('Mongoose '+ req.session.Client.name +' connection disconnected');
});
// If the Node process ends, close the Mongoose connection
process.on('SIGINT', function() {
client.close(function () {
console.log(req.session.Client.name +' connection disconnected through app termination');
process.exit(0);
});
});
//If pool has not been created, create it and Add new connection to the pool and set it as active connection
if(typeof(global.App.clients) === 'undefined' || typeof(global.App.clients[req.session.Client.name]) === 'undefined' && typeof(global.App.clientdbconn[req.session.Client.name]) === 'undefined')
{
clientname = req.session.Client.name;
global.App.clients[clientname] = req.session.Client.name;// Store name of client in the global clients array
activedb = global.App.clientdbconn[clientname] = client; //Store connection in the global connection array
console.log('I am now in the list of active clients ' + global.App.clients[clientname]);
}
global.App.activdb = activedb;
console.log('client connection established, and saved ' + req.session.Client.name);
next();
}
//if current client, does not match session client, then do not establish connection
else
{
delete req.session.Client;
client = false;
next();
}
}
else
{
if(typeof(req.session.Client) === 'undefined')
{
next();
}
//if client already has a connection make it active
else{
global.App.activdb = global.App.clientdbconn[req.session.Client.name];
console.log('did not make new connection for ' + req.session.Client.name);
return next();
}
}
}
}
module.exports = setclientdb;
Terakhir tapi tidak kalah pentingnya
Karena saya menggunakan kombinasi luwak dan luwak asli, Kami harus mengkompilasi model kami saat run time. Silakan lihat di bawah
Tambahkan ini ke app.js
. Anda
// require your models directory
var models = require('./models');
// Create models using mongoose connection for use in controllers
app.use(function db(req, res, next) {
req.db = {
User: global.App.activdb.model('User', models.agency_user, 'users')
//Post: global.App.activdb.model('Post', models.Post, 'posts')
};
return next();
});
Penjelasan:
Seperti yang saya katakan sebelumnya, saya membuat objek global untuk menyimpan objek koneksi database aktif:global.App.activdb
Kemudian saya menggunakan objek koneksi ini untuk membuat (mengkompilasi) model luwak, setelah saya menyimpannya di properti db dari objek req:req.db
. Saya melakukan ini agar saya dapat mengakses model saya di pengontrol saya seperti ini misalnya.
Contoh pengontrol Pengguna saya:
exports.list = function (req, res) {
req.db.User.find(function (err, users) {
res.send("respond with a resource" + users + 'and connections ' + JSON.stringify(global.App.clients, null, 4));
console.log('Worker ' + cluster.worker.id + ' running!');
});
};
Saya akan kembali dan membersihkan ini pada akhirnya. Jika ada yang ingin membantu saya, itu bagus.