Как обрабатывать асинхронный код синхронно только для конкретных запросов? - PullRequest
0 голосов
/ 13 октября 2019

Итак, у меня есть сервер Node.js, и я использую экспресс для маршрутизации. Допустим, у меня есть маршрут для обработки запросов POST, который состоит в основном из асинхронных функций (async / await) . Маршрут служит для создания учетной записи пользователя (вставка строки в базу данных Postgresql). Каждый аккаунт должен иметь уникальный адрес электронной почты. Когда я получаю запрос, первое, что делает маршрут, это запрос инструкции SELECT к БД, чтобы проверить, существует ли учетная запись с предоставленной электронной почтой - если это так, сервер отвечает определенным кодом статуса http и, если нет, новымАккаунт вставлен в БД. Это выглядит так:

var { data } = await selectAccount(email);
if (data) {
    return res.status(400).send({ "info": "Email already in use" });
} else {
    await insertAccount(email);
    return res.sendStatus(200);
}

Проблема в том, что, когда я получаю два или более запросов с одним и тем же письмом, с разницей всего в несколько миллисекунд. Если разница во времени между запросами составляет около 100 мс или более, все идет хорошо. Но с такой небольшой разницей во времени между запросами (скажем, 5 или 10 мс) код выполняется почти одновременно, поэтому select в обоих запросах не возвращает данных, и в БД вставляются две учетные записи с одинаковым адресом электронной почты.

Oneодним из способов решения этой проблемы будет установка уникального ограничения на электронную почту в базе данных, но я не хочу этого делать, потому что: 1. Я хочу изучить другие правильные способы решения этой проблемы, 2. Обработка исключений из БД и реагирование с определенным httpКоды состояния не всегда так просты, 3. Я имею дело с этой проблемой и на других маршрутах, где установка уникального ограничения невозможна.

Я думал об использовании async.queue, но я делаюНЕ хочу ставить запросы в очередь, только конкретные запросы с одинаковым телом (в данном случае с электронной почтой), и я не думаю, что для этого предназначен async.queue.

Другая вещь - использование Redis - но если запросыс разницей всего в несколько мс, Redis тоже может выйти из строя.

Я также искал решение, связанное с usiВ случае мьютекса, но безуспешно, поскольку реализации мьютекса принесли много сложностей. Спасибо за любую помощь

Правка (добавление функций - я использую модуль pg для объединения):

async function selectAccount(email) {
    var sql = "SELECT email FROM account WHERE email = $1";

    try {
        var { rows } = await pool.query(sql, [email]);
    } catch (err) {
        Log.e(err);
        return { data: new Error(JSON.stringify(err)) };
    }
    return { data: rows };
}

async function insertAccount(email) {
    var sql = "INSERT INTO account ( email ) VALUES ( $1 )";

    try {
        await pool.query(sql, [email]);
    } catch (err) {
        Log.e(err);
    }
    return;
}

Примечание: я не закончил свою работу, поэтому яулучшит обработку ошибок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...