Я подумал об этом и нашел возможное решение. Я еще не реализовал это, но я думаю, что это должно работать. По сути, это включает в себя выполнение следующего запроса (ПРИМЕЧАНИЕ: это специфично для MySQL):
select * from members where hour(convert_tz(now(),'UTC',timezone)) = 3;
Этот запрос выбирает всех участников, которые имеют текущее местное время между 3:00 и 3:59 AM, выполняя следующие действия:
- Получает текущее время сервера, используя
now()
, то есть время в формате UTC, поскольку сервер базы данных настроен на время UTC.
- Затем он преобразует это время с помощью функции
convert_tz()
в часовой пояс члена, как указано в столбце timezone
таблицы членов. Обратите внимание, что класс Member содержит поле часового пояса в формате «America / Los_Angeles».
- Затем он проверяет, какой час с помощью функции
hour()
, чтобы узнать, является ли он 3
, в течение 3 часов утра. * 10101 *
- Затем запрос возвращает всех участников, которые отвечают этим требованиям, и отправляет электронное письмо каждому из них.
Я немного обеспокоен тем, как каждый час выполнять преобразование и расчет часовых поясов для каждого члена системы. Мне придется протестировать вещи, чтобы увидеть, какую нагрузку она создает на базу данных, но, вероятно, она захлебнется миллионами или даже 10 тысячами пользователей.
Альтернатива, которая должна значительно облегчить нагрузку, но не такая элегантная, - это сделать следующее (ПРИМЕЧАНИЕ: этот код НЕ ПРОВЕРЕН!):
@Scheduled(cron="0 2 * * * *")
public void sendDailyReportEmail() {
Query query = session.createQuery(
"select distinct m.timezone from Member m");
List<String> timezones = query.list();
for (String timezone : timezones) {
DateTime now = new DateTime(DateTimeZone.forID(timezone));
if (now.getHourOfDay() == 3) {
Query query2 = session.createQuery(
"from Member where timezone = :zone");
query2.setParameter("zone", timezone);
List<Member> members = query2.list();
// send email reports
}
}
}
Этот код делает это:
- Выполнить метод через 2 минуты после часа, каждый час каждого дня
- Запросите в базе данных список всех уникальных часовых поясов в таблице участников.
- Для каждого найденного часового пояса определите, находится ли он в данный момент в 3:00.
- Если часовой пояс длится 3 часа, выберите всех участников этого часового пояса и отправьте им электронное письмо.
Это добавляет немного дополнительных издержек в начале каждого часа, но не требует обработки часового пояса для каждого пользователя. Скорее всего, в системе будет всего несколько десятков уникальных часовых поясов. Маловероятно, что у меня будут участники во всех 500+ часовых поясах.
И последнее. Вместо отправки электронной почты в 2 часа ночи я переместил ее в 3 часа ночи. Это связано с тем, что при переходе на летнее время весной время меняется с 2:00 до 3:00. Таким образом, нет такой вещи как 2:02, означающей, что электронные письма не были бы отправлены в тот день. Кроме того, осенью система может отправлять 2 электронных письма на пользователя, поскольку час повторяется. Мне нужно выяснить, меняются ли временные зоны за пределами США в разное время, потому что в 3 часа ночи может возникнуть проблема в других местах.