Переход через определенный промежуток времени в конечный автомат

В настоящее время я разрабатываю приложение Rails и использую гем state_machine, чтобы провести клиента через сложный процесс.

В нескольких состояниях процесса мне нужно инициировать события через определенный период времени. Например, если клиент не подтвердил, что он получил свой заказ через 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

Редактирование после тестирования моего предыдущего решения:

Как я могу вызвать переход через определенный период времени?

Спасибо,

Клеман


person ClemDoum    schedule 22.07.2013    source источник


Ответы (2)


Чтобы разбить решения на две основные группы, вы можете:

  1. Используйте решение для организации очередей Ruby/Rails, например DelayedJob, Resque или Sidekiq; или,
  2. Используйте кронджоб.

Первое, как правило, имеет наибольший смысл, если вы уже используете один из этих инструментов или знаете, что в конечном итоге вы собираетесь использовать один из них. Все они требуют довольно значительных усилий для запуска. Resque и Sidekiq требуют настройки сервера Redis, в то время как DelayedJob использует вашу существующую базу данных. Для 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, чтобы найти заказы в состоянии confirmed, которым 5+ дней. Затем мы перебираем каждую запись и запускаем событие not_received_by_5_days.

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

Запуская cron один или два раза в день (или чаще, если вы хотите, чтобы электронные письма отправлялись чаще), скрипт найдет каждый оставленный без присмотра заказ, которому не менее 5 дней, и проведет его через ваш рабочий процесс. Поскольку ваш код (должен) переводить людей в новое состояние после срабатывания события not_received_by_5_days, они больше не будут отображаться при последующих выполнениях скрипта и получат только одно напоминание.

person colinm    schedule 30.07.2013
comment
Еще раз спасибо, Колин! Использование задания cron будет решением для меня! Я нашел интересную документацию на Railscast о cronjob! Еще раз спасибо! - person ClemDoum; 31.07.2013

в качестве другого варианта гем state_manager(https://github.com/ghempton/state_manager) интегрируется с delayedjob и позволяет автоматически запускать переход через некоторое время:

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

  state :active
end
person Pavel K.    schedule 28.11.2013