почему переменная, определенная в модуле узла, является общей для двух пользователей - PullRequest
0 голосов
/ 20 февраля 2020

Я запускаю узел API-сервер с pm2 режим кластера , который будет взаимодействовать с mysql БД-сервером.

В модуле x.js У меня есть такой код:


let insertMappingQuery = ``;
...
...
const constructInsertMappingQuery = () => {
insertMappingQuery += `
    INSERT IGNORE INTO messages_mapping (message_id, contact_id)
    VALUES (` + message_id + `, ` + contact_id + ` + `);`;
}

Когда пользователь отправляет сообщение, функция вызывает модуль x, и для его сообщения выполняется приведенный выше код (скажем, message_id = 1 )

INSERT IGNORE INTO messages_mapping (message_id, contact_id)
    VALUES (1, some_id);

затем другой пользователь отправляет сообщение и код выполняется, скажем, message_id = 2 , однако запрос будет выглядеть так:

INSERT IGNORE INTO messages_mapping (message_id, contact_id)
    VALUES (1, some_id);
INSERT IGNORE INTO messages_mapping (message_id, contact_id)
    VALUES (2, some_id);

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

Это происходит не всегда, но часто (я бы сказал, 30-50%), и я не смог найдите любой шаблон, когда это произойдет.

Пользователи не должны делать это одновременно, может быть некоторая разница во времени (минуты или даже часы).

это может быть связано с переменная не очищается в памяти? или какая-то утечка памяти?

Я не понимаю, как два разных пользователя будут совместно использовать переменную.

Ответы [ 2 ]

0 голосов
/ 23 февраля 2020

Помните, что require кэширует модули и все последующие вызовы require получают одинаковые вещи, поэтому напишите что-нибудь, что экспортирует функцию или класс, чтобы вы могли безопасно вызывать / создавать экземпляры без переменные становятся общими.

Например:

const db = require(`your/db/connector`);

const Mapper = {
  addToMessageMapping: async function(messageId, contactId) {
    const query = `
      INSERT IGNORE INTO messages_mapping (message_id, contact_id)
      VALUES (${message_id}, ${contact_id});
    `;
    ...
    return db.run(query);
  },
  ...
}

module.exports = Mapper;

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

Теперь потребители этого кода просто верят, что следующее не имеет побочных эффектов:

const mapper = require('mapper.js');
const express, app, etc, whatever = ...

....

app.post(`/api/v1/mappings/message/:msgid`, (req, res, next) => {
  const post = getPOSTparamsTheUsualWay();

  mapper.addToMessageMapping(req.params.msgId, post.contactId)
        .then(() => next());
        .catch(error => next(error));

}, ..., moreMiddleware, ... , (req,res) => {
  res.render(`blah.html`, {...});
});

Также обратите внимание на этот шаблон строки существуют в частности для предотвращения компоновки строк путем конкатенации строк с +, весь смысл в том, что они могут принимать ${...} внутри них и шаблонить в «все, что находится в этих фигурных скобках» (переменные, вызовы функций , любой JS на самом деле).

(Второе, что у них есть, это то, что вы можете пометить их префиксом имени функции, и эта функция будет работать как часть шаблонного действия, но не нужно многим людям это на ежедневной основе. ${...} шаблонизирует, хотя? Каждый день, тысячи раз).

И, конечно, последнее замечание: похоже, вы создаете raw SQL, w Это всегда плохая идея. Используйте подготовленные операторы для любой библиотеки базы данных, которую вы используете: она поддерживает их и означает, что любой ввод пользователя сделан безопасным Прямо сейчас кто-то может опубликовать в вашем API с идентификатором сообщения ); DROP TABLE messages_mapping; -- и готово: ваша таблица исчезла. Веселые времена.

0 голосов
/ 23 февраля 2020

Очевидно, я не знал, что require модуль будет кешировать его и использовать повторно. Таким образом, глобальные переменные в этом модуле также будут кэшироваться.

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

delete require.cache[require.resolve('replaceWithModulePathHere')]

Пример:

let somefuncThatNeedsModuleX = () => {
  delete require.cache[require.resolve('./x')];
  const x = require('./x');
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...