Sha256: 11af18b31a67dbbda0aaac2ae61771976973414dee9cb4095a1271de9a8676ac

Contents?: true

Size: 1.77 KB

Versions: 1

Compression:

Stored size: 1.77 KB

Contents

require 'status_workflow/version'
require 'timeout'

module StatusWorkflow
  class InvalidTransition < StandardError; end

  def self.included(klass)
    klass.extend ClassMethods
  end

  def self.redis=(redis)
    @redis = redis
  end

  def self.redis
    @redis or raise("please set StatusWorkflow.redis=")
  end

  module ClassMethods
    def status_workflow(transitions)
      transitions.inject({}) do |memo, (from_status, to_statuses)|
        to_statuses.each do |to_status|
          memo[to_status] ||= []
          memo[to_status] << from_status
        end
        memo
      end.each do |to_status, from_statuses|
        define_method "enter_#{to_status}!" do
          lock_key = "status_workflow/#{self.class.name}/#{id}"
          Timeout.timeout(8, nil, "timeout waiting for #{self.class.name}/#{id} lock") do
            until StatusWorkflow.redis.set(lock_key, true, nx: true, ex: 4)
              sleep 0.2
            end
          end
          # got the lock, i have 3 (4 expiry on lock - 1 for safety) seconds to set it
          Timeout.timeout(3, nil, "timeout waiting for #{self.class.name}/#{id} status update") do
            # depend on #can_enter_X to reload
            raise InvalidTransition, "can't enter #{to_status} from #{status}, expected #{from_statuses.join('/')}" unless send("can_enter_#{to_status}?")
            update_columns status: to_status, status_changed_at: Time.now
          end
          StatusWorkflow.redis.del lock_key
          true
        end
        define_method "can_enter_#{to_status}?" do
          reload
          from_statuses.include? status&.to_sym
        end
        define_method "enter_#{to_status}_if_possible" do
          begin; send("enter_#{to_status}!"); rescue InvalidTransition; false; end
        end
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
status_workflow-1.0.0 lib/status_workflow.rb