Моделирование бесконечно повторяющихся задач в расписании (приложение, похожее на календарь) - PullRequest
11 голосов
/ 18 марта 2011

Это был камень преткновения.Предупреждение: следующее не вопрос, скорее объяснение того, что я придумал.У меня вопрос - есть ли у вас лучший способ сделать это?Есть ли какая-то распространенная техника для этого, с которой я не знаком?Похоже, это тривиальная проблема.

Итак, у вас есть модель задач.Вы можете создавать задания, выполнять их, уничтожать их.Тогда у вас есть повторяющиеся задачи.Это как обычная задача, но к ней прикреплено правило повторения.Тем не менее, задачи могут повторяться бесконечно - вы можете пойти на год вперед в расписании, и вы должны увидеть, как задача появляется.

Поэтому, когда пользователь создает повторяющуюся задачу, вы не хотите создавать тысячизадачи на сто лет в будущее, и сохранить их в базе данных, верно?Поэтому я начал думать - как вы их создаете?

Один из способов - создать их при просмотре расписания.Таким образом, когда пользователь перемещается на месяц вперед, будут созданы любые повторяющиеся задачи.Конечно, это означает, что вы больше не можете просто работать с записями задач в базе данных.Каждая операция SELECT для задач, которые вы когда-либо выполняете, должна быть в контексте определенного диапазона дат, чтобы запускать повторяющиеся задачи в этом диапазоне дат для сохранения.Это бремя обслуживания и производительности, но выполнимое.

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

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

Однако, когда пользователь перемещается по задачам в расписании, как мы узнаем, чтоконкретный момент новая задача повторения должна быть создана?Мы просим правило повторения: «Эй, я должен сохранить задачу на этот день?»и это говорит да или нет.Если на этот день уже есть задача для этого повторения, мы ее не создаем.Все хорошо, кроме того, что пользователь также сможет просто удалить одну из повторяющихся задач, которая была автоматически сохранена.В этом случае, следуя нашей логике, система заново создаст задачу, которая была удалена.Нехорошо.Таким образом, это означает, что мы должны продолжать сохранять задачу, но пометить ее как удаленную задачу для этого повторения.Мех.

Как я сказал в начале, я хочу знать, занимался ли кто-нибудь еще этой проблемой и может ли дать здесь архитектурный совет.Это должно быть так грязно?Есть ли что-нибудь более изящное, что мне не хватает?

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

Ответы [ 3 ]

8 голосов
/ 03 ноября 2012

Я знаю, что это старый вопрос, но я только начинаю изучать его для своего собственного приложения, и я нашел эту статью Мартина Фаулера, освещающую: Повторяющиеся события для календарей

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

Практически для вашего случая использования это может означать, что вы сохраняете задачу со свойством «временное выражение», которое называется schedule. рекуррентный камень ice_cube имеет возможность сериализации себя в свойство активной записи примерно так :

class Task < ActiveRecord::Base
  include IceCube
  serialize :schedule, Hash

  def schedule=(new_schedule)
    write_attribute(:schedule, new_schedule.to_hash)
  end

  def schedule
    Schedule.from_hash(read_attribute(:schedule))
  end
end

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

Проблема в том, что вы действительно не можете запросить базу данных о задаче, которая попадает в определенный диапазон дат, потому что вы сохранили только правило для выполнения задач, а не сами задачи. В моем случае я подумываю добавить свойство типа «next_recurrence_date», которое будет использоваться для выполнения некоторой базовой сортировки / фильтрации. Вы даже можете использовать это, чтобы бросить задачу в очередь, чтобы что-то сделать в следующую повторяющуюся дату. (Например, проверьте, прошла ли эта дата, а затем сгенерируйте ее заново. Вы можете даже сохранить «заархивированную» версию задачи, когда пройдет ее следующая повторяющаяся дата.)

Это исправляет вашу проблему с «что если задача обновляется», поскольку задачи не сохраняются, пока они не остались в прошлом.

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

3 голосов
/ 18 марта 2011

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

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

Я разделил свои модели на Boardroom (очевидно) и Event (что являетсябронирование, связанное с пользователем).Я думаю, что была и модель соединения, но это было давно.Когда пользователь пытается зарезервировать зал заседаний, используется следующий процесс:

  1. Попытка забронировать номер в первый доступный день (выполняется с помощью пользовательского интерфейса календаря, аналогично тому, как Календарь Google создает события)
  2. Если это однократный, все готово
  3. Если это повторяющееся событие, попробуйте сразу забронировать следующие 6 событий на основе данного правила (еженедельно, раз в две недели, ежемесячно);Если это не удается, из-за конфликта, закажите те, которые вы можете, по электронной почте конфликты пользователю
  4. Книга на следующий год или до даты, когда повторение заканчивается в фоновом задании;Следуйте правилу разрешения конфликтов из # 3

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

Если пользователь обновил исходное бронирование (например, изменил время и дату), у него / нее была возможность обновить только один или каждый следующий повтор.Если последнее было выбрано, шаги 3 и 4 повторно запускаются после удаления существующих событий.

Если это очень похоже на Календарь Google, то вы полностью поняли мой подход:)

Надеюсь, это поможет.

1 голос
/ 18 марта 2011

Я лично думаю, что (в python, который я хорошо знаю), и ruby ​​(который я знаю менее хорошо, но это динамический язык, и поэтому я думаю, что концепции отображают 1: 1), вы должны использовать генераторы. Как это для минималистичного ответа? Теперь, когда вы генерируете свой пользовательский интерфейс, вы передаете ссылку на генератор, и он генерирует нужные вам объекты по мере их запроса.

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

Зачем вам нужно размножаться объектами? Что вам действительно нужно, так это виртуальные элементы управления отображением данных (для Интернета или рабочего стола), также известные как «подкачка страниц» в веб-контекстах, и вы можете думать о своем графике как о бесконечной электронной таблице сгенерированных по запросу без верхней строки и нет нижнего ряда. Единственные значения, которые необходимо вычислить (рассчитать, а не хранить), - это те значения, которые отображаются прямо сейчас и видны пользователю.

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