Mongodb Node Driver - действительно ли имеет значение, когда я вызываю db.close (), или мне повезло? - PullRequest
0 голосов
/ 07 июня 2018

Я обнаружил, что db.close (), похоже, не закрывается, пока не завершатся все чтения или записи независимо от того, когда он вызывается.Это на самом деле то, что я хотел бы, но я хочу убедиться, что это предполагаемое поведение, а не только мне повезло.У меня есть некоторый код, подобный этому:

...
{
  collection.insertMany(...).then(()=> { console.log("inserted") })
  collection.deleteMany(...).then(()=> { console.log("deleted") })
}).then(() =>
{
  console.log("will close");
  client.close();
}).catch((reason) => { console.log(reason) });

Я получаю вывод вроде:

will close
deleted
inserted

, но без ошибок, и при дальнейшем тестировании соответствующие записи были фактически вставлены и удалены.В документации мы видим, что они вызывают db.close (), каким бы ни был окончательный обратный вызов, но я тогда этого не делал.Это надежно?Я не уверен, как реструктурировать мой код, чтобы сделать более понятным, что закрытие происходит после обоих insertMany и deleteMany - возможно, я должен был использовать promise.all.

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

Мне кажется, что код выше выдает insertManyи deleteMany перед client.close () независимо, так что я бы подумал, что mongodb знает, что есть ожидающие операции, поэтому закроется соответствующим образом.Может кто-нибудь привести пример сценария того, как client.close () может быть вызван преждевременно?Если предполагается, что ошибка в любой из этих операций может привести к преждевременному вызову client.close (), я предлагаю добавить

{
  collection.insertMany(...).then(()=> { console.log("inserted") })
  collection.deleteMany(...).then(()=> { console.log("deleted") })
}).then(() =>
{
  console.log("will close");
}).catch((reason) => { console.log(reason) })
  .then(() => { client.close() })

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Честно говоря, вам не только «везет» с действиями, которые необходимо решить перед вызовом client.close(), но также может быть «потенциальная» проблема с двумя операторами, работающими параллельно.

В идеале вы должны вместо этого использовать bulkWrite() и сделать «одиночный» запрос с обоими действиями, содержащимися в нем.«Один запрос» также имеет «один ответ», поэтому нет проблем с ожиданием разрешения нескольких обещаний:

collection.bulkWrite(
  [
    ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
    { "deleteMany": { "filter": filterCondition } }
  ]
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

Действие по умолчанию bulkWrite() состоит в том, что операции выполняются "упорядочено "и выполняется последовательно в том же порядке, в котором они были представлены в массиве" представленных действий ".Array.map(), используемый здесь для создания действий insertOne, на самом деле является именно тем, что метод insertMany() фактически делает в реализации базового драйвера.

ВФакт ВСЕ, что такие методы драйвера фактически называют базовые методы «Bulk API» как современный способ работы.bulkWrite() явно абстрагируется от фактического «Bulk API», чтобы изящно понизить требования к «устаревшему» API при подключении к экземпляру MongoDB ранее, чем MongoDB 2.6.

Другой способ сделать это - «параллельное» выполнение, явно указав "ordered": false:

collection.bulkWrite(
  [
  ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
  { "deleteMany": { "filter": filterCondition } }
  ],
  { "ordered": false }
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

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

Помимо «параллелизма», общее назначение "ordered": falseразрешить продолжение «по ошибке».В таком случае все «пакетные» действия фактически предпринимаются, и в ответе об исключительной ситуации вы получаете подробную информацию о том, в каких «индексных позициях» в массиве предусмотренных действий произошел какой-либо сбой.

Поведение тогда"sort" выполняется в "mimicry" следующим вызовом Promise.all():

Promise.all([
  collection.insertMany(..., { "ordered": false }).then(()=> { console.log("inserted") }),
  collection.deleteMany(...).then(()=> { console.log("deleted") })
]).then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

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

А для «полноты» вы всегда можете, конечно, «связать» обещания:

  collection.insertMany(...)
    .then(() => console.log("inserted")),
    .then(() => collection.deleteMany(...)
    .then(()=> console.log("deleted"))
    .then(() => console.log("will close"))
    .catch(e => console.error(e))
    .then(() => client.close());

Таким образом«все» выполняется последовательно, но, конечно, все они запускают отдельные запросы.

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

0 голосов
/ 07 июня 2018

Вам нужно дождаться завершения запросов.Вы можете сделать это, вернув Promise.all([query1, query2]), который разрешится, когда оба обещания, возвращенные запросами, будут выполнены.Кроме того, используйте .finally() -метод Promise , чтобы обеспечить вызов client.close(), даже если есть ошибка.С вашим текущим кодом, если произойдет ошибка, client.close() не будет вызван.

...
{
  return Promise.all([
    collection.insertMany(...).then(()=> { console.log("inserted") }),
    collection.deleteMany(...).then(()=> { console.log("deleted") })
  ]);
}).then(() => {
  console.log("will close");
}).catch((reason) => {
  console.log(reason);
}).finally(() => {
  client.close();
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...