Подтвердить что ты не робот

Как установить таймаут в запросе Mongoose?

Я использую Mongoose с очень большой базой Mongo, и я хочу, чтобы дорогостоящие запросы, такие как MySet.find({}), истекали через 10 секунд.

Я пробовал установить тайм-аут сокета в моем соединении, но сервер выходит из строя, если превышен тайм-аут:

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

Я пробовал передать параметр maxTimeMS в find, но это не имеет никакого эффекта:

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

Любые идеи?

4b9b3361

Ответ 1

Вы можете сделать это с Query#maxTime метода Query#maxTime.

Так что в вашем случае вы бы назвали это как:

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

Вы можете подтвердить это правильно, установив параметр maxTimeMS, включив отладку Mongoose через mongoose.set('debug', true); и тогда вы увидите консольный вывод для этого запроса, который выглядит следующим образом:

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

Ответ 2

TL; DR:

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

Вы можете проверить этот запрос:

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

Почему это работает:

Вы можете использовать модификаторы запросов

И особенно этот: $maxTimeMS

Будьте осторожны: этот оператор устарел в mongo Shell с версии v3.2

Ответ 3

Я думаю, что это должно сработать.

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

Ответ 4

Это шаблон, который я начал использовать много.

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

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

Ответ 5

Наконец-то я начал работать. Во-первых, я предотвращаю сбой сервера после сбоя сокета (то есть запроса):

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

Затем, каждый раз, когда я хочу запросить базу данных, я отключусь и подключись к базе данных, установив socketTimeoutMS на 10000:

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

Это отключение запроса после 10 секунд выполнения.