Nano Hash - криптовалюты, майнинг, программирование

Django: запуск процесса каждый день в указанное локальное время пользователя

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

В настоящее время у меня есть задание cron (на другом сервере), которое запускает метод каждые, например, 5 минут и смотрит, нужно ли что-то запланировать на следующие (скажем) 10 минут.

Я сохраняю значение времени и локальный часовой пояс пользователя для каждого задания.

Как лучше всего это сделать?

Сейчас я работаю над функцией, которая:

  • Преобразует время сервера в локальное время пользователя.
  • Создает локальный объект даты и времени, локализованный «сегодня» и время, указанное пользователем
  • Проверяет, не прошло ли 10 минут после срабатывания будильника пользователя.
  • Если это время между 23:50 и 23:59:59, а пользователь установил время с 00:00 до 00:10, локализованное «сегодня» создается с датой «завтра». (например, если до полуночи осталось 2 минуты, а пользователь хочет провести событие в 12:01, я вычисляю событие с завтрашней датой)
  • Я устанавливаю поле last_scheduled, когда оно запланировано, и поле last_fired, чтобы гарантировать, что я не отправлю несколько.

Если это произойдет в течение 10 минут, я планирую задачу (поток, что угодно), которая вскоре запустится.

Не совсем уверен в лучшей практике здесь. Должен ли я:
Продолжать проверять, есть ли у меня какие-либо задачи в будущем, и планировать краткосрочные задачи?
Предварительно генерировать все мои времена заранее (может быть, за месяц?)
Сделать что-то совершенно другое?
Я также думал, что всегда могу просто запланировать "следующее" событие, но Меня беспокоит то, что, скажем, мой сервер отключится, и я пропущу "следующее" событие на следующий день. никогда не будет запланировано.

Уточнить:

  • Я сохраняю время и часовой пояс для каждого задания (например, полдень в США/Восток).
  • Я делаю поправку на летнее время, поэтому при расчете времени UTC я беру сегодняшнюю дату в формате UTC, конвертирую в местное время, а затем использую его для расчета дельты. Я использую pytz и normalize(), чтобы убедиться, что у меня нет проблем с переходом на летнее время.
  • У меня есть время последнего запланированного и последнего запуска, чтобы убедиться, что я не выполняю дважды.

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

Редактировать: После изучения ответов ниже я пришел к следующему менее худшему сценарию:

У меня есть следующие поля

  • Время выполнения последнего события
  • В последний раз событие было запланировано
  • Время выполнения следующего события
  • Время суток и часовой пояс

Я рассчитываю и устанавливаю next_run_time всякий раз, когда я: обновляю событие или запускаю событие. Это делает следующее:

  • Если у него есть последнее время выполнения, вычисляется next_run_time, по крайней мере, через 2 часа в будущем (избегайте проблем с летним временем, добавляя некоторые отступы).
  • Если мероприятие никогда не проводилось, запланируйте как минимум 15 минут в будущем (избегайте нескольких одновременных расписаний).

Моя запланированная работа делает следующее:

  1. Проверяет все события, которые имеют next_run_time в ближайшие 15 минут и не запланированы в данный момент. Любые совпадения запланированы.

Планирование работы:

  • Планирует задание и устанавливает задание как запланированное «сейчас»

Когда задача выполняется (успех):

  • last_run_time обновляется до «сейчас»
  • next_run_time пересчитывается

Если задача не удалась: - Задание переносится на 30 секунд вперед. Если сбой превышает пороговое значение (в моем случае просрочено на 3 минуты), задача прерывается, а next_run_time пересчитывается на следующий день. Это регистрируется и, надеюсь, не слишком часто

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


Ответы:


1

Я не буду касаться специфики Python/Django, так как это не моя область знаний. Но в целом планировщик задач описываемого вами типа должен действовать следующим образом (ИМХО):

  • Отделите определение расписания от времени выполнения
  • Определение расписания должно быть определено по местному времени пользователя и включать идентификатор часового пояса.
  • Время выполнения должно быть указано в формате UTC.
  • Когда задача выполняется, она должна рассчитать следующее время выполнения по расписанию.

Давайте рассмотрим пример.

  • Пользователь говорит: «Выполнять каждую ночь в полночь по восточному времени США».
  • Мы храним расписание «Ежедневно, 00:00, America/New_York».
  • Мы рассчитываем, что первое время выполнения будет 2013-06-30T04:00:00Z.
  • Используя любой механизм, который вам нравится, запускайте задание во время выполнения. Если вы периодически опрашиваете задания, которые необходимо запустить, просто посмотрите, прошло ли время (ExecTime ‹= utcnow). Если вы можете положиться на систему событий, задание cron и т. д., это, вероятно, лучше.
  • Когда задание выполняется, используйте расписание для расчета следующего времени выполнения.

Почему расписание по местному времени? Что ж, в случае восточного времени оно будет переходить от -5 часов от UTC до -4 часов из-за перехода на летнее время. Если расписание строго основано на UTC, то после перехода на летнее время вы обнаружите, что задания выполняются в то время, которое пользователь считает неправильным.

Кроме того, вам следует подумать об обработке сбоев, повторных попыток и т. д. И вы не хотите, чтобы задание выполнялось более одного раза за запланированное выполнение, поэтому вам может понадобиться способ пометить его как «в процессе», если у вас есть более одного проверка программы на задачи. Иногда вам может понадобиться более сложная стратегия блокировки, чтобы несколько рабочих процессов не выполняли одну и ту же задачу. Это немного выходит за рамки того, что я могу здесь написать.

Вам также следует подумать о том, как вы хотите справляться с неоднозначностью местного времени, вызванной переходом на летнее время. Думая о переходах в стиле «отката», если пользователь говорит бегать в «1:30 каждую ночь», но есть одна ночь в году, когда 1:30 происходит дважды, что вы хотите сделать? Если вы не сделаете ничего особенного, он запустится при первом появлении - обычно это дневное время. Пользователь может ожидать стандартное время, поэтому вам, возможно, придется проверить это. Даже если вы просто бежите в полночь, вы не освобождаетесь от этого решения. Есть несколько часовых поясов, которые переходят ровно в полночь (например, Бразилия).

Если все это кажется слишком трудоемким, вы можете просто поискать планировщик заданий, который уже написан. Например, Quartz на Java или Quartz.Net в стеке .Net. Я не знаком с ним напрямую, но поиск дал APScheduler для Python, который выглядит красиво. аналогичный.

29.06.2013
  • Ценю любую информацию здесь. Чтобы уточнить, я храню по местному времени, чтобы избежать проблем с летним временем, и у меня действительно есть, например, Daily 00:00 New York. У меня есть функция to_next_utc_time(), которая дает мне следующую среду выполнения после now() 30.06.2013
  • На самом деле я реализовал решение Quartz на стороне .net. Я просто не мог оправдать отказ от некоторых отличных/дешевых хостингов для Linux. FWIW, тем не менее, я запускаю моно-приложения в производстве на своей основной работе, и моно на героку было заманчиво. Спасибо за ссылку Apscheduler, я думаю, что включу ее по крайней мере в половину решения здесь. 30.06.2013

  • 2

    (Я бы поместил это как комментарий, но SO не разрешает их для новых пользователей) взгляните также на сельдерей, возможно, это поможет http://docs.celeryproject.org/en/latest/userguide/tasks.html

    30.06.2013
  • Спасибо, я посмотрю. 30.06.2013
  • Вау, я думаю, это именно то, что я ищу. stackoverflow .com/questions/7848512/ 30.06.2013
  • Похоже, что Celery будет выполнять периодические задачи с часовыми поясами и интегрируется с pytz, так что мой голос за него тоже. Хорошая находка! 30.06.2013
  • Celery Beat docs.celeryproject.org/en/2.5/userguide/periodic- tasks.html, кажется, соответствует всем требованиям, но будет запускать задачи в определенном часовом поясе по всем направлениям. Я думаю, что, возможно, стоит пойти и изменить celery cron, чтобы принять аргумент часового пояса. 30.06.2013
  • если это подходит в вашем случае, я бы сохранил все расписания пользователей в UTC (если вы хотите, вы также можете запомнить часовые пояса для пользовательского интерфейса или другой информации) и использовать apply_async с etas, когда определенная задача выполняется в первый раз, когда вы переносите ее на следующий день/время . 30.06.2013
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..