Class: AsyncCache::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/async_cache/store.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Store

Returns a new instance of Store.



5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/async_cache/store.rb', line 5

def initialize(opts = {})
  @worker_klass =
    if opts[:worker_klass]
      opts[:worker_klass]
    elsif opts[:worker]
      AsyncCache::Workers.worker_for_name opts[:worker]
    else
      raise ArgumentError, 'Must have a :worker_klass or :worker option'
    end

  @backend = opts[:backend] || AsyncCache.backend
end

Instance Attribute Details

#backendObject

Returns the value of attribute backend.



3
4
5
# File 'lib/async_cache/store.rb', line 3

def backend
  @backend
end

#worker_klassObject

Returns the value of attribute worker_klass.



3
4
5
# File 'lib/async_cache/store.rb', line 3

def worker_klass
  @worker_klass
end

Instance Method Details

#determine_strategy(has_cached_data:, needs_regen:, synchronous_regen:) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/async_cache/store.rb', line 59

def determine_strategy(has_cached_data:, needs_regen:, synchronous_regen:)
  case
  when !has_cached_data
    # Not present at all
    :generate
  when needs_regen && synchronous_regen
    # Caller has indicated we should synchronously regenerate
    :generate
  when needs_regen && !worker_klass.has_workers?
    # No workers available to regnerate, so do it ourselves; we'll log a
    # warning message that we can alert on
    AsyncCache.logger.warn "No workers running to handle AsyncCache jobs"
    :generate
  when needs_regen
    :enqueue
  else
    :current
  end
end

#enqueue_generation(key:, version:, expires_in:, block:, arguments:) ⇒ Object



94
95
96
97
98
99
100
101
102
# File 'lib/async_cache/store.rb', line 94

def enqueue_generation(key:, version:, expires_in:, block:, arguments:)
  worker_klass.enqueue_async_job(
    key:        key,
    version:    version,
    expires_in: expires_in,
    block:      block.to_source,
    arguments:  arguments
  )
end

#fetch(locator, version, options = {}, &block) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/async_cache/store.rb', line 18

def fetch(locator, version, options = {}, &block)
  options = options.dup  # Duplicate to avoid side effects
  version = version.to_i # Versions must *always* be convertible to integers

  # Expires-in must be an integer if present, nil if not
  expires_in = options[:expires_in] ? options[:expires_in].to_i : nil

  block_arguments = check_arguments(options.delete(:arguments) || [])

  # Serialize arguments into the full cache key
  key = ActiveSupport::Cache.expand_cache_key Array.wrap(locator) + block_arguments

  cached_data, cached_version = @backend.read key

  strategy = determine_strategy(
    :has_cached_data   => !!cached_data,
    :needs_regen       => version > (cached_version || 0),
    :synchronous_regen => options[:synchronous_regen]
  )

  context = {
    :key        => key,
    :version    => version,
    :expires_in => expires_in,
    :block      => block,
    :arguments  => block_arguments
  }

  case strategy
  when :generate
    return generate_and_cache context

  when :enqueue
    enqueue_generation context
    return cached_data

  when :current
    return cached_data
  end
end

#generate_and_cache(key:, version:, expires_in:, block:, arguments:) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/async_cache/store.rb', line 79

def generate_and_cache(key:, version:, expires_in:, block:, arguments:)
  block_source = block.to_source

  # Mimic the destruction-of-scope behavior of the worker in development
  # so it will *fail* for developers if they try to depend upon scope
  block = eval(block_source)

  data = block.call(*arguments)

  entry = [data, version]
  @backend.write key, entry, :expires_in => expires_in

  return data
end