【问题标题】:Can Rails ActiveJob be used to enqueue a block of code?Rails ActiveJob 可以用于将代码块排入队列吗?
【发布时间】:2015-06-05 08:44:10
【问题描述】:

是否可以使用 Rails 的新 ActiveJob API 来对代码块进行排队?有时我不想在那里生成工作并将逻辑移到那里。它将知识从我宁愿保留在那里的模型中移出。

让我举一个我目前正在从事的项目中的例子。这有点奇怪,但它让我将所有知识都保留在我的模型中。

# app/models/subscription.rb
class Subscription < ActiveRecord::Base
  def cancel
    CancelSubscriptionJob.perform(self)
  end

  def cancel_tasks
    # stuff that takes a long time
  end
end

# app/jobs/cancel_subscription_job.rb
class CancelSubscriptionJob < ActiveJob::Base
  def perform(subscription)
    subscription.cancel_tasks
  end
end

我觉得我要绕过我的手肘来获取我的 !@# 在这里。我想可以说cancel_tasks 方法属于这项工作,但我不喜欢这样。我想查看模型中的取消任务,我一直在保留此类知识的其余部分。

还有一个论点是这些都不属于模型,但在 Rails 的某个时刻,我觉得所有人都告诉我要做的就是提取、提取和提取,直到我没有完成任何实际工作.

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4.2


    【解决方案1】:

    理论上你可以使用一些元编程来动态构建一个子类,它遵循 ActiveJob 规范,但我认为这比你需要的更混乱。

    我只是创建一个调用模型方法的瘦 ActiveJob,实际上是它的包装器。

    顺便说一句,保持模型精简并专注于持久性而不是您想要排队的那种业务逻辑也是一个很好的论据。在这种情况下,从模型中提取业务逻辑是一件好事。有人说你可以使用作业类来保持逻辑,但我个人更喜欢让它们保持精简,而不是在service classes 中使用逻辑。

    【讨论】:

    • 我的模型中肯定有大量的业务逻辑。这似乎是放置这些东西的正确位置。我用一个例子更新了原始问题以使其更清楚。我目前正在使用一些奇怪的东西来保留模型中的所有内容。您可以从示例中看出为什么我觉得生成作业是不必要的步骤。
    • 嗯,在更复杂的应用程序/模型中将业务逻辑从持久性中分离出来是有很好的论据的,但是有时它可能是矫枉过正的。撇开这一点不谈,隔离作业的一个很好的理由是帮助管理您的队列部署。我确实同意在您的问题中制作一个微不足道的包装器是反干燥的;但是,如果您或其他人正在管理实时排队系统,那么如果您必须深入研究任意代码以找到这些工作的创建位置,那将是很困难的。如果它们都在 app/jobs 之类的文件夹中,那就更干净了。
    • @RyanBurnette 提取的原因是因为具有单一职责的类(和方法)易于重用和重构。因此,将“提取”视为让每个类/方法服务于单一职责的尝试。这使未来的变化更容易(即更灵活的系统)。所以我同意mahemoff 关于服务类的话,但会强调单一责任原则作为原因。对于您的情况, SubscriptionTasksCancellingService 可能会做得很好(并且将来根据需要更容易替换,而不是必须删除 Subscription 模型)。
    • @pdobb 谢谢你帮助我正确看待事情。
    【解决方案2】:

    我相信这样做是可以接受的:

    # app/models/subscription.rb
    class Subscription < ActiveRecord::Base
      def cancel
        CancelSubscriptionJob.perform_later(self)
      end
    
      def cancel_tasks
        # stuff that takes a long time
      end
    
      class CancelSubscriptionJob < ActiveJob::Base
        def perform(subscription)
          subscription.cancel_tasks
        end
      end
    end
    

    当认为给定类的唯一用例将来自另一个类的上下文时,通常会使用这种模式。 (或者,至少在第一个类的命名空间中。)

    例如,上面的方法意味着:Subscription 的实例方法仍然可以直接引用CancelSubscriptionJob,但是要引用Subscription 之外的作业,您必须将其命名为Subscription::CancelSubscriptionJob .

    无论如何,除了其他开发人员可能希望这个 ActiveJob 出现在 /app/jobs/ 文件夹中之外,我不明白为什么这会是一件坏事(所以可能需要去打猎)。但总的来说,这是一种相当标准的方法。

    【讨论】:

    • 这对我来说似乎是一个更好的模式。我也意识到这将允许我在模型规范中保留对 cancel_tasks 内容的所有测试。
    猜你喜欢
    • 1970-01-01
    • 2019-08-21
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 2016-06-05
    • 2023-04-03
    相关资源
    最近更新 更多