2015-12-02 2 views
1

Я создаю приложение, в котором у меня есть 2 разных модуля. Одним из них является соединение с mongodb, а другой модуль - соединение redis для управления сеансом. В этом случае каждый модуль имеет 2 события и подключается. Вот пример одного из модулей:Подождите несколько событий из разных модулей, а затем запустите сервер

var sessionStore = new SessionStore(app.get("sessionStore")); 

sessionStore.client.on("error", function(err) { 

    console.error("[SessionStore]:", "connection error:", err.address + ":" + err.port, "for process:", process.pid); 

    var sessionStoreError = new Error("Session store error"); 
    sessionStoreError.message = "Session store connection error"; 
    sessionStoreError.code = err.code; 
    sessionStoreError.address = err.address; 
    sessionStoreError.port = err.port; 

    app.emit("error", sessionStoreError); 

}); 


sessionStore.client.on("connect", function() { 

    console.log("[SessionStore]:", "connection established:", app.get("sessionStore").host + ":" + app.get("sessionStore"), "for process:", process.pid); 
    app.emit("ready"); 

}); 

Почти точно так же происходит с модулем MongoDB.

То, что я хотел бы достичь (избегая пирамиду обреченности) что-то вроде этого, но когда оба Redis и соединение MongoDB из своих модулей успешны:

app.on("ready", function(){ 
    app.listen(app.get("port")); 
}); 

Имейте в виде, что я мог бы гнездо каждого модуля внутри другого и, возможно, потребуют последовательных модулей внутри обработчиков подключений, а затем испускать последнее событие для приложения, но это не изящно, я полагаю, согласно моим вкусам.

Есть ли элегантный способ подождать 2 события, а затем запустить сервер?

+0

Вы должны проверить обещания, и подождать, пока все обещания, используя обещание.all (promisesArray) – mkinawy

ответ

1

bootable обеспечивает уровень инициализации, который вы также можете использовать для приложений Express. Это не дает строгого решения по вашему вопросу («Подождите, пока не произойдет 2 события»), но он разрешает проблему ожидания нескольких асинхронных модулей перед запуском сервера.

Вы можете добавить фазы загрузки для MongoDB и Redis. После того, как все фазы готовы, вызывается обратный вызов на app.boot() (вы можете проверить наличие ошибок при инициализации), и когда все будет в порядке, приложение может начать прослушивать входящие соединения.

Вот сеанс магазин пример превратился в фазе загрузки:

module.exports = function(app) { 
    app.phase(function(done) { 
    var sessionStore = new SessionStore(app.get("sessionStore")); 

    sessionStore.client.once("error", function(err) { 
     console.error("[SessionStore]:", "connection error:", err.address + ":" + err.port, "for process:", process.pid); 

     var sessionStoreError = new Error("Session store error"); 
     sessionStoreError.message = "Session store connection error"; 
     sessionStoreError.code = err.code; 
     sessionStoreError.address = err.address; 
     sessionStoreError.port = err.port; 

     return done(sessionStoreError); 
    }); 

    sessionStore.client.once("connect", function() { 
     console.log("[SessionStore]:", "connection established:", app.get("sessionStore").host + ":" + app.get("sessionStore"), "for process:", process.pid); 
     return done(); 
    }); 
    }); 
}; 

Ваш основной код будет выглядеть примерно так:

var bootable = require('bootable'); 
var express = require('express') 
var app  = bootable(express()); 

require('./boot/session-store')(app); // loads the module above 
require('./boot/mongodb')(app);  // a MongoDB boot phase 

// This is the equivalent of your `app.on('ready', ...)` 
app.boot(function(err) { 
    if (err) throw err; 
    app.listen(app.get("port")); 
}); 
1

Из верхней части моей головы, вот это лучшее решение, которое я мог думать:

Я думаю, что наиболее «элегантный» путь, как вы предложили, чтобы позвонить каждый модуль с async.waterfall, и когда оба из них выполнены, отправьте событие в приложение. Я думаю, что это хорошее решение, но единственная проблема заключается в том, что вы теряете время, активируя модуль последовательно и не в одно и то же время.

Чтобы сэкономить время, может быть, вы можете использовать менее «элегантное» решение так:

Модуль Redis будет испускать мероприятие под названием «redisReady» и модуль MongoDB будет испускать один называется «mongoReady», и в основным модулем будет:

app.on("redisReady", function(){ 
    redisModuleReady = true; 
    if (mongoModuleReady) { 
     app.listen(app.get("port")); 
    } 
}); 

app.on("mongoReady", function(){ 
    mongoModuleReady = true; 
    if (redisModuleReady) { 
     app.listen(app.get("port")); 
    } 
}); 

Это намного менее «красиво», но экономит время.

Несомненно, есть больше решений, но это то, к чему я пришел.

+0

Да, я тоже думал об этом, это печально, что в Eventemitter есть встроенный метод из нескольких событий, подобных этому случаю – Syd

+0

Вы прав, я искал и ничего не вышло, хотя это разумная особенность. Если я не пропустил что-то, я думаю, что мой ответ - лучший способ пойти. –

Смежные вопросы