class SidekiqSimpleDelay::Proxy

Simple proxy object that handles enqueuing delay workers via `method_missing`

Public Class Methods

new(performable, target, options = {}) click to toggle source
# File lib/sidekiq_simple_delay/generic_proxy.rb, line 8
def initialize(performable, target, options = {})
  @performable = performable
  @target = target
  @opts = options
end

Public Instance Methods

method_missing(name, *args) click to toggle source
# File lib/sidekiq_simple_delay/generic_proxy.rb, line 14
def method_missing(name, *args)
  worker_args = {
    'm' => name,
    'args' => args
  }

  # check to make sure there are no keyword or block args
  method_args_sig = @target.method(name).parameters

  num_req_key_args = method_args_sig.count { |p| p[0] == :keyreq }
  num_opt_key_args = method_args_sig.count { |p| p[0] == :key }
  num_var_key_args = method_args_sig.count { |p| p[0] == :keyrest }

  uses_keyword_args = num_req_key_args > 0 || num_opt_key_args > 0 || num_var_key_args > 0
  raise ArgumentError, 'Cannot delay methods with named arguments' if uses_keyword_args

  num_block_args = method_args_sig.select { |p| p[0] == :block }.length
  raise ArgumentError, 'Cannot delay methods with named block argument' if num_block_args > 0

  # Calling class methods is always permitted
  if @target.is_a?(Class)
    worker_args['target_klass'] = @target.name
  # If this is an instance, it has to tell us what args we would use
  # to reinitialize it in the worker. If `#new` takes no args, that is also ok
  elsif @target.respond_to?(:initialize_args) || @target.method(:initialize).arity == 0
    worker_args['target_klass'] = @target.class.name
    # Verify it works with arrays, hashes, named arguments, and lists of arguments
    # These args will be passed to `simple_delay_initialize` if defined
    # or new otherwise
    worker_args['init_args'] =
      if @target.respond_to?(:initialize_args)
        @target.initialize_args
      else
        []
      end
  else
    # This is an instance of a class that is not simple delay compatible
    raise ArgumentError, "Objects of class #{@target.class} must implement " \
                         '#initialize_args or be calling a method with an arity of 0 to be delayed'
  end

  # the args have to be simple and convertable to JSON
  raise ArgumentError, 'args are not serializable, cannot use simple_delay' unless Utils.simple_object?(worker_args)

  @performable.client_push({ 'class' => @performable, 'args' => [worker_args] }.merge(@opts))
end