Выполняйте ежедневные действия в определенное время в зависимости от местного часового пояса пользователя. - PullRequest
5 голосов
/ 14 сентября 2010

Моему Java-приложению необходимо отправлять электронные письма всем пользователям один раз в день.Я хотел бы доставить его примерно в 2 часа ночи по местному времени каждого пользователя.Таким образом, пользователь в Нью-Йорке получит сообщение в 2 часа ночи по Америке / Нью-Йорк.Пользователь в Лос-Анджелесе получит сообщение в 2 часа ночи по времени Америки / Лос-Анджелеса.Мой почтовый процесс будет запускаться один раз в час.

Я планирую использовать функции геолокации HTML5 или геолокацию IP-адресов, чтобы автоматически определять часовой пояс каждого пользователя при регистрации.Конечно, пользователь может изменить часовой пояс вручную, если эти значения неверны.Я намереваюсь сохранить выбранный часовой пояс в объекте User в виде строки идентификатора часового пояса, например «America / New_York».Это будет сохраняться в базе данных в виде строки, но при необходимости это можно изменить.

Что следует учесть:

  • Мне необходимо учитывать летнее время, поэтому пользователь всегдаполучает письмо около 2 утра.Это означает, что я не могу просто хранить GMT-8 или аналогичные смещения UTC в пользовательском объекте.Часть года Лос-Анджелес находится в GMT-7, а другие части - в GMT-8.
  • Другой вопрос SO содержит ответы, которые предлагают хранить информацию о смещении, но я неПосмотрите, как это будет работать, так как время в разных местах может меняться в течение года.Я не собираюсь обновлять все часовые пояса моих пользовательских объектов всякий раз, когда в мире происходит событие изменения часового пояса.
  • Я использую JodaTime в своем приложении, поэтому я могу воспользоваться этим, если это поможет.
  • Я использую Hibernate для запросов к базе данных и хотел бы найти решение, которое можно было бы обработать в запросе hibernate, без необходимости обрабатывать сотни тысяч пользовательских записей в Java.

Я использую функции cron Spring Scheduling (через Quartz), чтобы запускать метод через 2 минуты после часа каждый час дня.Сейчас большинство моих пользователей находятся в Америке / Лос-Анджелесе, поэтому я вручную заставляю отправлять всю почту в 2:02 по тихоокеанскому времени.Следующий метод выполняется каждый час по адресу: 02 за час, но он проверяет время вручную и работает только в том случае, если текущее время в Лос-Анджелесе составляет 2 часа.Это означает, что пользователи в других местах получат электронное письмо не в 2 часа. * 10101

@Scheduled(cron="0 2 * * * *")
public void sendDailyReportEmail()  {
    DateTime now = new DateTime(DateTimeZone.forID("America/Los_Angeles"));
    if (now.getHourOfDay() != 2) {
        log.info("Not 2AM pacific, so skipping email reports");
        return;
    }
    // send email reports
}
1021 * Итак, мне нужно выполнить запрос к базе данных, который даст мне всех пользователей, имеющих местное время в2:00 AM часа, в зависимости от часового пояса в их пользовательском объекте.Есть мысли о том, как этого добиться?

1 Ответ

2 голосов
/ 03 декабря 2010

Я подумал об этом и нашел возможное решение. Я еще не реализовал это, но я думаю, что это должно работать. По сути, это включает в себя выполнение следующего запроса (ПРИМЕЧАНИЕ: это специфично для MySQL):

select * from members where hour(convert_tz(now(),'UTC',timezone)) = 3;

Этот запрос выбирает всех участников, которые имеют текущее местное время между 3:00 и 3:59 AM, выполняя следующие действия:

  1. Получает текущее время сервера, используя now(), то есть время в формате UTC, поскольку сервер базы данных настроен на время UTC.
  2. Затем он преобразует это время с помощью функции convert_tz() в часовой пояс члена, как указано в столбце timezone таблицы членов. Обратите внимание, что класс Member содержит поле часового пояса в формате «America / Los_Angeles».
  3. Затем он проверяет, какой час с помощью функции hour(), чтобы узнать, является ли он 3, в течение 3 часов утра. * 10101 *
  4. Затем запрос возвращает всех участников, которые отвечают этим требованиям, и отправляет электронное письмо каждому из них.

Я немного обеспокоен тем, как каждый час выполнять преобразование и расчет часовых поясов для каждого члена системы. Мне придется протестировать вещи, чтобы увидеть, какую нагрузку она создает на базу данных, но, вероятно, она захлебнется миллионами или даже 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
        }
    }
}

Этот код делает это:

  1. Выполнить метод через 2 минуты после часа, каждый час каждого дня
  2. Запросите в базе данных список всех уникальных часовых поясов в таблице участников.
  3. Для каждого найденного часового пояса определите, находится ли он в данный момент в 3:00.
  4. Если часовой пояс длится 3 часа, выберите всех участников этого часового пояса и отправьте им электронное письмо.

Это добавляет немного дополнительных издержек в начале каждого часа, но не требует обработки часового пояса для каждого пользователя. Скорее всего, в системе будет всего несколько десятков уникальных часовых поясов. Маловероятно, что у меня будут участники во всех 500+ часовых поясах.

И последнее. Вместо отправки электронной почты в 2 часа ночи я переместил ее в 3 часа ночи. Это связано с тем, что при переходе на летнее время весной время меняется с 2:00 до 3:00. Таким образом, нет такой вещи как 2:02, означающей, что электронные письма не были бы отправлены в тот день. Кроме того, осенью система может отправлять 2 электронных письма на пользователя, поскольку час повторяется. Мне нужно выяснить, меняются ли временные зоны за пределами США в разное время, потому что в 3 часа ночи может возникнуть проблема в других местах.

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