这是一个很大的绊脚石。警告:以下不是问题,而是对我的想法的解释。我的问题是——你有更好的方法吗?是否有一些我不熟悉的常用技术?看起来这是一个微不足道的问题。
所以你有任务模型。您可以创建任务、完成任务、销毁任务。然后你有经常性的任务。它就像常规任务一样,但它附加了一个重复规则。但是,任务可以无限期地重复——您可以在计划中提前一年,您应该会看到任务出现。
因此,当用户创建一个循环任务时,您不会想在未来百年内构建数千个任务,并将它们保存到数据库中,对吧?所以我开始思考 — 如何创建它们?
一种方法是在您查看日程安排时创建它们。因此,当用户提前一个月移动时,将创建任何重复性任务。当然,这意味着您不能再简单地使用任务的数据库记录。您曾经对任务执行的每个 SELECT 操作都必须在特定日期范围的上下文中,以便触发该日期范围内的重复任务以持续存在。这是一种维护和性能负担,但可行。
好的,但是原始任务呢?每个循环任务都与创建它的循环规则相关联,并且每个循环规则都需要知道启动循环的原始任务。后者很重要,因为您需要在用户浏览他们的日程安排时将原始任务克隆到新日期。我想也是可行的。
但是如果更新了原始任务会发生什么?这意味着现在当我们浏览日程表时,我们将创建从修改后的任务中克隆出来的重复性任务。这是不可取的。所有隐式持久化的重复任务都应该以添加重复时原始任务的方式显示。因此,我们需要单独存储原始任务的副本,并从中克隆,以便重复执行。
但是,当用户浏览日程中的任务时,我们如何知道在特定点是否需要创建新的重复任务?我们询问重复规则:“嘿,我应该坚持这一天的任务吗?”它说是或否。如果这一天已经有此重复的任务,我们不会创建一个。一切都很好,除了用户还可以简单地删除已自动保留的重复任务之一。在这种情况下,按照我们的逻辑,系统将重新创建已删除的任务。不好。所以这意味着我们需要继续存储任务,但将其标记为本次重复的已删除任务。嗯。
正如我在开头所说的,我想知道是否有人解决了这个问题并且可以在这里提供架构建议。一定要这么乱吗?我还缺少什么更优雅的东西吗?
更新:由于这个问题很难完美回答,我会赞成对设计/架构最有帮助的见解,它对这类问题有最好的帮助/权衡比。它不必包含所有细节。
最佳答案
我知道这是一个老问题,但我刚刚开始为我自己的应用研究这个问题,我发现 Martin Fowler 的这篇论文很有启发性:Recurring Events for Calendars
我的主要收获是使用他所谓的“时间表达式”来确定预订是否在特定日期范围内,而不是尝试将无限数量的事件(或您的情况下的任务)插入数据库。
实际上,对于您的用例,这可能意味着您使用名为 schedule
的“时间表达式”属性存储任务。 ice_cube recurrence gem能够将自身序列化为事件记录属性 like so :
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 看起来非常灵活,甚至允许您指定重复规则的异常(exception)情况。 (假设您只想删除任务的一次出现,而不是全部。)
问题是您无法真正查询数据库以查找属于特定日期范围内的任务,因为您只存储了创建任务的规则,而不是任务本身。对于我的情况,我正在考虑添加一个属性,如“next_recurrence_date”,它将用于进行一些基本的排序/过滤。您甚至可以使用它来将任务放入队列中,以便在下一个重复日期完成某件事。 (比如检查该日期是否已过,然后重新生成它。您甚至可以在下一个重复日期过后存储任务的“存档”版本。)
这解决了“如果任务更新了怎么办”的问题,因为任务在过去之前不会持久化。
无论如何,我希望这对试图为自己的应用考虑这一点的人有所帮助。
关于ruby-on-rails - 在时间表中对无限期重复的任务进行建模(类似日历的 Rails 应用程序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5346839/