Class: SidekiqSmartCache::Promise

Inherits:
Object
  • Object
show all
Defined in:
lib/sidekiq_smart_cache/promise.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass: nil, object: nil, object_param: nil, method:, args: nil, cache_tag: nil, expires_in: 1.hour, job_interlock_timeout: nil) ⇒ Promise

Returns a new instance of Promise.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/sidekiq_smart_cache/promise.rb', line 10

def initialize(klass: nil, object: nil, object_param: nil, method:, args: nil,
               cache_tag: nil, expires_in: 1.hour, job_interlock_timeout: nil)
  if object
    @klass = object.class.to_s
    @object_param = object.to_param
  elsif klass
    @klass = klass.to_s
    @object_param = object_param
  else
    raise "Must provide either klass or object"
  end
  raise "Must provide method" unless method
  @method = method.to_s
  @expires_in = expires_in.to_i
  @job_interlock_timeout = job_interlock_timeout || @expires_in
  @args = args
  @cache_tag = cache_tag
end

Instance Attribute Details

#argsObject

Returns the value of attribute args.



3
4
5
# File 'lib/sidekiq_smart_cache/promise.rb', line 3

def args
  @args
end

#expires_inObject

Returns the value of attribute expires_in.



3
4
5
# File 'lib/sidekiq_smart_cache/promise.rb', line 3

def expires_in
  @expires_in
end

#job_interlock_timeoutObject

Returns the value of attribute job_interlock_timeout.



3
4
5
# File 'lib/sidekiq_smart_cache/promise.rb', line 3

def job_interlock_timeout
  @job_interlock_timeout
end

#klassObject

Returns the value of attribute klass.



3
4
5
# File 'lib/sidekiq_smart_cache/promise.rb', line 3

def klass
  @klass
end

#methodObject

Returns the value of attribute method.



3
4
5
# File 'lib/sidekiq_smart_cache/promise.rb', line 3

def method
  @method
end

#object_paramObject

Returns the value of attribute object_param.



3
4
5
# File 'lib/sidekiq_smart_cache/promise.rb', line 3

def object_param
  @object_param
end

#timed_outObject

Returns the value of attribute timed_out.



4
5
6
# File 'lib/sidekiq_smart_cache/promise.rb', line 4

def timed_out
  @timed_out
end

Instance Method Details

#cache_tagObject



29
30
31
32
33
34
35
36
37
38
# File 'lib/sidekiq_smart_cache/promise.rb', line 29

def cache_tag
  @cache_tag ||= begin
    [
      klass,
      (object_param || '.'),
      method,
      (Digest::MD5.hexdigest(args.compact.to_json) if args.present?)
    ].compact * '/'
  end
end

#enqueue_job!Object



48
49
50
# File 'lib/sidekiq_smart_cache/promise.rb', line 48

def enqueue_job!
  Worker.perform_async(klass, object_param, method, args, cache_tag, expires_in)
end

#execute_and_wait(timeout, raise_on_timeout: false, stale_on_timeout: false) ⇒ Object Also known as: fetch



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/sidekiq_smart_cache/promise.rb', line 90

def execute_and_wait(timeout, raise_on_timeout: false, stale_on_timeout: false)
  previous_result = result
  if previous_result&.fresh?
    # found a previously fresh message
    @timed_out = false
    return previous_result.value
  else
    start

    # either a job was already running or we started one, now wait for an answer
    if redis.wait_for_done_message(cache_tag, timeout.to_i)
      # ready now, fetch it
      log('promise calculator job finished')
      @timed_out = false
      result.value
    elsif previous_result && stale_on_timeout
      log('promise timed out awaiting calculator job, serving stale')
      previous_result.value
    else
      log('promise timed out awaiting calculator job')
      @timed_out = true
      raise TimeoutError if raise_on_timeout
    end
  end
end

#execute_and_wait!(timeout, stale_on_timeout: false) ⇒ Object Also known as: fetch!



52
53
54
# File 'lib/sidekiq_smart_cache/promise.rb', line 52

def execute_and_wait!(timeout, stale_on_timeout: false)
  execute_and_wait(timeout, raise_on_timeout: true, stale_on_timeout: stale_on_timeout)
end

#existing_value(allow_stale: false) ⇒ Object



64
65
66
67
68
# File 'lib/sidekiq_smart_cache/promise.rb', line 64

def existing_value(allow_stale: false)
  if((existing = result) && (allow_stale || existing.fresh?))
    existing.value
  end
end

#interlockObject



40
41
42
# File 'lib/sidekiq_smart_cache/promise.rb', line 40

def interlock
  @_interlock ||= Interlock.new(cache_tag, job_interlock_timeout)
end

#perform_nowObject



44
45
46
# File 'lib/sidekiq_smart_cache/promise.rb', line 44

def perform_now
  Worker.new.perform(klass, object_param, method, args, cache_tag, expires_in)
end

#ready_within?(timeout) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
73
# File 'lib/sidekiq_smart_cache/promise.rb', line 70

def ready_within?(timeout)
  execute_and_wait(timeout)
  !timed_out
end

#resultObject



56
57
58
# File 'lib/sidekiq_smart_cache/promise.rb', line 56

def result
  Result.load_from(cache_tag)
end

#stale_value_available?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/sidekiq_smart_cache/promise.rb', line 60

def stale_value_available?
  !!result&.stale?
end

#startObject



79
80
81
82
83
84
85
86
87
88
# File 'lib/sidekiq_smart_cache/promise.rb', line 79

def start
  # Start a job if no other client has
  if interlock.lock_job?
    log('promise enqueuing calculator job')
    enqueue_job!
  else
    log('promise calculator job already working')
  end
  self # for chaining
end

#timed_out?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/sidekiq_smart_cache/promise.rb', line 75

def timed_out?
  !!timed_out
end