2015-03-12 19 views
8

Sto usando Mongoose con un database Mongo molto grande e voglio che query costose come MySet.find({}) scadano dopo 10 secondi.Come si imposta un timeout su una query Mongoose?

Ho provato a installare un timeout presa sulla mia connessione, ma il server si blocca se il timeout è superato:

var options = {server: {socketOptions: {socketTimeoutMS: 10000}}}; 
var conn = mongoose.connect('mongodb://localhost/my_db', options); 

Ho provato passando l'opzione maxTimeMS alla funzione find, ma che doesn' Non ha alcun effetto:

MySet.find({}, {}, {timeout: true, maxTimeMS: 10000}, function(err, doc) {}); 

Qualche idea?

+0

Stai usando MongoDB 2.6 o superiore? –

+0

'mongo --version' dice' Versione shell MongoDB: 2.6.8'. –

+0

Sembra che il supporto di Mongoose per l'opzione 'maxTimeMS' sia stato [aggiunto in 3.8.13] (https://github.com/learnboost/mongoose/blob/master/History.md#3813--2014-07-15). Qual è la tua versione Mongoose? – JohnnyHK

risposta

-1

Penso che questo dovrebbe funzionare.

db.mycoll.find(). MaxTimeMS (50)

+0

Funzionerebbe per il driver MongoDB nativo, ma non funziona con Mongoose. –

-7

ho finalmente ottenuto lavorando. Per prima cosa ho impedire al server dal crash quando la presa (vale a dire una query) timeout:

//don't crash the server if a query times out 
mongoose.connection.on('error', function() {}); 

Poi, ogni volta che voglio per interrogare il database, ho disconnettersi da e ricollegare al database, l'impostazione socketTimeoutMS a 10000:

mongoose.disconnect(); 
mongoose.connect('mongodb://localhost/my_db', { 
    server: {socketOptions: {socketTimeoutMS: 10000}} 
}); 
MySet.find({}, function(err, doc) {}); 

Questo interrompe la query dopo esattamente 10 secondi di esecuzione.

+0

Disconnettere/riconnettere su ogni query sarebbe costoso giusto? – avmohan

+3

L'overhead che stai pagando ricollegando ogni query rende questo approccio inutilizzabile per tutto tranne le app più semplici. –

6

È possibile eseguire questa operazione con il metodo Query#maxTime non documentato in Mongoose, ma fa parte della libreria mquery che Mongoose utilizza per la sua fluente interfaccia di query.

Quindi nel tuo caso, si potrebbe chiamare come:

MySet.find({}).maxTime(10000).exec(function(err, doc) { ... }); 

È possibile confermare che è correttamente impostare l'opzione maxTimeMS abilitando il debug Mongoose via mongoose.set('debug', true); e poi vedrete output su console per questa query che sembra Mi piace:

Mongoose: myset.find({}) { maxTimeMS: 10000, safe: true, fields: {} } 
+0

sai se questo può essere fatto anche su 'populate()'? Come qui: http://stackoverflow.com/questions/42398696/mongoose-model-populate-query-timeout – Zlatko

+0

Esiste un'opzione per aggiungere questo maxTime a livello globale a tutte le query? –

-1

Questo è lo schema che ho iniziato ad usare molto.

// Default time out timeout in ms 
const DEFAULT_TIME_OUT = 500; 

// Default timeout message 
const DEFAULT_MESSAGE = `Timeout fetching data(${DEFAULT_TIME_OUT}ms)`; 

// Function that triggers a Promise's reject after a set amount of time 
function timeoutReject(reject, message, timeout) { 
    setTimeout(function(){ 

    // Reject the Promise if the time is reached 
    reject(message || DEFAULT_MESSAGE); 
    }, timeout || DEFAULT_TIME_OUT); 
}; 

function youAreNotAuthentic() { 
    // Logic to validate user and request return boolean 
}; 

// Throw error if the user cannot access this data 
function youCantTouchThis() { 
    throw new Error('You cannot access this data.'); 
}; 

// Function to request data 
function getDataById(_id) { 
    // First check if this is authentic 
    if (youAreNotAuthentic()) youCantTouchThis(); 

    // Return a Promise 
    return new Promise((resolve, reject) => { 

    // Set a timeout to reject if we do not get a response in x time 
    timeoutReject(reject, 'Custom Message', 300); 

    // Could look like this to just use the defaults 
    // timeoutReject(reject); 

    // Query for the data 
    Collection.findOne({ _id }).then(data => { 

     // Resolve the Promise with the retrieved data 
     resolve(data); 
    }); 
    }); 
}; 

In questo modo ho un timeout predefinito applicato alla maggior parte delle richieste, ma se ho bisogno di regolare su base per chiamata allora posso. Oppure posso essere reso consapevole delle aree che necessitano di una migliore indicizzazione.

+0

Alcuni hanno suggerito e approvato il "preventivo angolare singolo" per essere una citazione normale. Questo non funzionerà. È pensato per essere una stringa di modelli. 'è corretto non' ''. – bcbrian

0

TL; DR:

MySet.find({ $query: { /*Query here*/ }, $maxTimeMS: 10000 }); 

è possibile verificare con questa query:

MySet.find({ $query: {"$where": "sleep(100) || true"}, $maxTimeMS: 10000 }); 

Perché funziona:

È possibile utilizzare Query modifiers

E especialy Questo uno: $maxTimeMS

Prestare attenzione: questo operatore è deprecato in Mongo Shell dal v3.2

Problemi correlati