How do I set a timeout on a Mongoose query?

前端 未结 5 757
刺人心
刺人心 2020-12-19 01:48

I am using Mongoose with a very large Mongo database, and I want costly queries like MySet.find({}) to time out after 10 seconds.

I\'ve tried setting a

相关标签:
5条回答
  • 2020-12-19 02:26

    You can do this with the Query#maxTime method.

    So in your case, you would call it as:

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

    You can confirm it's correctly setting the maxTimeMS option by enabling Mongoose debugging via mongoose.set('debug', true); and then you'll see console output for this query that looks like:

    Mongoose: myset.find({}) { maxTimeMS: 10000, safe: true, fields: {} }
    
    0 讨论(0)
  • 2020-12-19 02:37

    I think this should work.

    db.mycoll.find().maxTimeMS(50)

    0 讨论(0)
  • 2020-12-19 02:42

    TL;DR:

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

    You can test with this query :

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

    Why it works:

    You can use Query modifiers

    And especialy this one : $maxTimeMS

    Be careful : this operator is deprecated in mongo Shell since v3.2

    0 讨论(0)
  • 2020-12-19 02:47

    I finally got it working. First I prevent the server from crashing when the socket (i.e. a query) times out:

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

    Then, every time I want to query the database, I disconnect from and reconnect to the database, setting socketTimeoutMS to 10000:

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

    This cuts off the query after precisely 10 seconds of execution.

    0 讨论(0)
  • 2020-12-19 02:52

    This is the pattern I have started to use a lot.

    // 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);
        });
      });
    };
    

    This way I have a default timeout applied to most requests but if I need to adjust on an per call basis then I can. Or I can be made aware of areas that need better indexing.

    0 讨论(0)
提交回复
热议问题