为什么像StackOverflow这样有徽章的网站会使用某种延迟任务来确定何时授予新徽章?

14

Stackoverflow有一个很棒的勋章系统。有一件事情我注意到了,那就是勋章不会立即颁发,但有时在我满足条件后似乎会有一定的延迟。我在其他一些也有勋章的网站上也注意到了这一点。

这可能是因为他们使用了延迟作业,定期扫描以查看是否需要授予新的勋章。我在这里也看到了这种方法的建议:
如何实现勋章?

然而,我真的不明白为什么这是必要的,并且在我的实现中倾向于简单地拥有一个系统,在执行相关操作(例如发布新评论)后,调用checkAwardBadge函数,该函数检查用户是否符合获得新评论徽章的条件。

在速度方面,我想所有相关的用户统计数据都将简单地存储在User的子模型中,例如UserStats,这样每次不需要再次计算评论数量,只需进行简单的查询即可。

我认为,我倾向的系统应该快速且非常容易理解。这里有我所忽略的缺点吗,为什么有必要用延迟作业来复杂化事情?

澄清一下: 我计划有一个抽象类Achievements,每个实际的成就都是Achievements的一个实现。每个成就将具有一个checkAwardBadge函数,它可以从控制器中调用,甚至是延迟作业(如果我选择这条路),或者任何时候,来检查用户是否获得了某个勋章。因此,成就代码将集中在一起。

4个回答

16
虽然这与您描述的情况只有松散的相似之处,但我认为讨论我们在工作中所做的事情可能有助于阐明此方法一部分的原因。
我在一个实时算法交易公司工作。我们软件的主要功能之一是处理来自供应商的市场数据。
现在,对于每个市场变化事件,都需要进行某些处理。我们运行分析,设置在某些情况下生效的安全触发器等等。但是我们不惜一切代价避免让响应市场事件的代码被所有“次要”逻辑所膨胀。
这里的理由是,我们的数据通过网络从数据提供商传输,我们需要保证数据流畅无阻。我们的软件可能每秒处理约10,000个市场变动事件。如果处理这些市场事件的时间太长,则数据流开始堵塞,我们尽快地对市场作出反应的能力也将受到影响。
这样做的后果是,处理新市场事件的代码非常简洁。事件会更新一个价格,就这样而已。至于所有其他逻辑,需要定期运行,并通过一个包含所有尚未被该逻辑检查的事件的队列来执行。
这使我们拥有一个非常敏感且没有数据阻塞的线程,而另一个处理传入事件并对其进行更重要的计算。以这种方式将工作分成两部分可以保持一切运行顺畅。
我承认这只是与您的问题有间接关系,但在我看来,不检查与徽章相关的逻辑的原因可能完全相同。您不希望通过在操作发生的精确时刻执行不太关键的逻辑来减慢服务器上的每个操作。总体策略是保持快速操作的快速(即,基本上所有用户操作),并将需要更耗时的工作委托给次要进程运行,这些进程可能会经常运行,但并不针对每个此类操作。

+1 绝对同意,并且非常好地解释了理论基础,我认为。 - Gian

15

你的实现可能适用于简单场景(如您所描述的场景),但如果情况变得更加复杂,你的解决方案会出现以下问题:

  1. 在每个操作中进行了不必要的检查
  2. 给每个操作增加了性能惩罚
  3. 无法扩展
  4. 没有一个集中的地方来管理所有规则。

(1) 和 (2) 对此的性能惩罚非常轻微。只需对数据库进行简单的一行查询,然后执行一些简单的逻辑,如(X>30)。 (3) 你能解释一下为什么这样做无法扩展吗? (4) 实际上可以。我计划创建一个成就类,每个成就都是一个子类。然后,在大多数情况下,我只需要在控制器代码中添加一行代码,以调用相关徽章的 checkAwardBadge 方法即可。 - William Jones
2
只是一个例子:假设您有一个操作,例如删除评论,它不会触发任何徽章,但稍后您需要在用户删除评论时授予徽章,您必须返回查找所有删除评论的代码并添加调用checkAwardBadge。想象一下更复杂的情况。 - Eduardo Molteni
3
由于当你有100,000个以上的用户和10,000,000个动作时,你必须在每个单独的用户动作之后查询数据库,因此它无法扩展。相反,如果你将工作转移到一个(等待它)工作线程中,那么该线程可以在后台运行,并定期更新每个用户的徽章。 它可以变得更智能,例如只扫描自上次运行线程以来创建的活动等。 - BryanH

4

如果某个动作被执行后立即撤消,可能不会获得徽章。


2
我一直认为延迟是因为提供静态内容更快。我认为这在高流量网站上很常见,定期更新静态内容而不是为每个Web请求生成它。
定期任务只需生成新的静态内容,并且会非常频繁地运行,但不会像每个页面请求那样频繁。

事实上,静态内容只有在内容(或页面组件/小部件)更新时才需要更新。 - BryanH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接