在状态机中经过一段时间后转换

时间:2013-07-22 10:06:45

标签: ruby-on-rails timer state-machine transitions

我目前正在开发一个Rails应用程序,我正在使用state_machine gem来指导客户完成一个复杂的过程。

在流程的多个状态下,我需要在一段时间后触发事件。例如,如果客户在5天后未确认收到订单,我想自动向他发送电子邮件并进入包裹跟踪流程。

class Order < ActiveRecord::Base



    state_machine :initial => :confirmed do

        after_transition :on => :not_received_by_5_days, do |order, transition|
            order.send_email
            order. .....
            order. .....

        event :customer_confirmation do
            transition :confirmed => :order_received
        end

        event :not_received_by_5_days do
            transition :confirmed => :parcel_tracking_process
        end

        def send_email
            blabla
        end
    end

end

在测试我之前的解决方案后进行编辑:

如何在一段时间后触发过渡?

谢谢,

克莱门特

2 个答案:

答案 0 :(得分:0)

要将解决方案分为两大类,您可以:

  1. 使用Ruby / Rails排队解决方案,例如DelayedJobResqueSidekiq;或者,
  2. 使用cronjob。
  3. 如果您已经使用其中一种工具或者知道您最终会使用其中一种工具,前者往往最有意义。所有这些都需要相当大的努力才能开始。当DelayedJob使用您现有的数据库时,Resque和Sidekiq需要配置Redis服务器。 Resque还需要一个插件来安排作业,而DelayedJob和Sidekiq本身支持调度作业。这三者都需要创建工作模型并配置工作人员才能运行。

    假设您拥有cron访问权限,后者非常简单。用Ruby编写自己的脚本,并安排它通过cron自动运行。

    我有一段时间没有使用过state_machine,但是这应该可行(如果没有,它可以解决这个问题):

    #!/usr/bin/env /path/to/project/bin/rails runner
    Order.where(state: 'confirmed').where("created_at <= #{5.days.ago}").find_each do |o|
      o.not_received_by_5_days
    end
    

    这里发生了什么?创建Order对象后,它就会进入confirmed状态。因此,要查找需要稍微调整的订单,我们可以运行ActiveRecord查询以查找5天以上confirmed状态的订单。然后,我们遍历每条记录并触发not_received_by_5_days事件。

    整个过程由Rails运行管理,它加载你的Rails环境并在那里执行你的脚本代码(就像使用Rails控制台一样,但没有人工干预)。

    每天由cron运行一次或两次(如果您希望电子邮件更频繁地运行,则更频繁地运行),脚本将找到至少5天的每个无人注意的订单并将其移动到您的工作流程中。由于您的代码(应该)在not_received_by_5_days事件触发后将人员移动到新状态,因此它们将不再显示在后续脚本执行中,并且只会收到一个提醒。

答案 1 :(得分:0)

作为另一个选项,state_manager(https://github.com/ghempton/state_manager)gem与delayedjob集成,并允许在一段时间后自动通过触发转换:

class UserStates < StateManager::Base
  state :submitted do
    event :activate, :transitions_to => :active, :delay => 2.days
  end

  state :active
end