Сервер Node.js/Koa2 — выполнение задания через несколько минут после запроса

У меня есть приложение Koa2/Node.js (использующее async/await), и я хочу выполнить задание X минут после запроса, где X — случайное количество минут в диапазоне от 20 - 100 (я хочу использовать его для отправки автоматических приветственных писем пользователям, которые зарегистрируются, и чтобы они выглядели так, как будто они были отправлены лично мной).

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


person Maciej Krawczyk    schedule 17.08.2017    source источник
comment
Почему бы вам не использовать SendGrid и не создавать шаблоны, чтобы процесс электронной почты был автоматизирован и электронные письма отправлялись мгновенно. Гораздо лучший пользовательский интерфейс, чем ожидание 100 минут, чтобы использовать новый сайт, на который вы только что зарегистрировались.   -  person VtoCorleone    schedule 17.08.2017
comment
На самом деле я использую SendGrid, и процесс электронной почты автоматизирован, я просто хочу автоматизировать задержку. И сделать так, чтобы это выглядело так, как будто оно было отправлено человеком, а не ботом.   -  person Maciej Krawczyk    schedule 17.08.2017
comment
Если вы можете, задание хрона будет лучше, чем setTimeout.   -  person VtoCorleone    schedule 17.08.2017
comment
Вы должны делегировать отправку письма и работать вне запроса. Установить флаг в базе данных и использовать задание cron? Или с чем-то более причудливым (redis pub/sub, очередь rabbitMQ и обработка сообщения с помощью скрипта?)   -  person thesearentthedroids    schedule 20.08.2017
comment
@MaciejKrawczyk: Не могли бы вы рассказать, как вы в итоге решили свою проблему?   -  person Damaged Organic    schedule 07.09.2017


Ответы (1)


Очередь команд, такая как rabbitMQ или обертка вокруг Redis (с pub/sub или SETEX), кажется накладной для такой простой задачи.

Тайм-ауты в течение относительно длительных периодов с потенциально N запросами кажутся немного неудобными, но Node.js setTimout() на самом деле является оболочкой вокруг uv_timer функции в libuv, которая предназначена для обработки огромного количества таймеров поверх основного механизма уведомлений ОС.

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

const schedule = require('node-schedule');

const getRandomMsAmount = (from, to) => {
  const minutes = Math.floor(Math.random() * to) + from;
  return minutes * 60 * 1000;
};

const getDateAfterMs = (ms) => {
  const nowTimestamp = Number(new Date());
  return new Date(nowTimestamp + ms);
};

const dueDate = getDateAfterMs(getRandomMsAmount(20, 100));
const emailJob = schedule.scheduleJob(dueDate, () => {
  // logging, updating database, etc.
});

Если во время обработки что-то пойдет не так, указанное задание можно отменить:

emailJob.cancel();

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

person Damaged Organic    schedule 02.09.2017