Class: LazyData::Dict

Inherits:
Object
  • Object
show all
Defined in:
lib/lazy_data/dict.rb

Overview

This expands on Value by providing a lazy key-value dictionary. Each key uses a separate Value; hence multiple keys can be in the process of computation concurrently and independently.

Instance Method Summary collapse

Constructor Details

#initialize(retries: nil, lifetime: nil, &block) ⇒ Dict

Create a LazyData::Dict.

You must pass a block that will be called to compute the value the first time it is accessed. The block takes the key as an argument and should evaluate to the value for that key, or raise an exception on error. To specify a value that expires, use LazyData.expiring_value. To raise an exception that expires, use LazyData.raise_expiring_error.

You can optionally pass a retry manager, which controls how subsequent accesses might try calling the block again if a compute attempt fails with an exception. A retry manager should either be an instance of Retries or an object that duck types it.

Parameters:

  • retries (Retries, Proc) (defaults to: nil)

    A retry manager. The default is a retry manager that tries only once. You can provide either a static retry manager or a Proc that returns a retry manager.

  • lifetime (Numeric, nil) (defaults to: nil)

    The default lifetime of a computed value. Optional. No expiration by default if not provided. This can be overridden in the block by returning LazyData.expiring_value or calling LazyData.raise_expiring_error explicitly.

  • block (Proc)

    A block that can be called to attempt to compute the value given the key.



51
52
53
54
55
56
57
# File 'lib/lazy_data/dict.rb', line 51

def initialize(retries: nil, lifetime: nil, &block)
  @retries = retries
  @default_lifetime = lifetime
  @compute_handler = block
  @key_values = {}
  @mutex = ::Thread::Mutex.new
end

Instance Method Details

#await(key, *extra_args, transient_errors: nil, max_tries: 1, max_time: nil) ⇒ Object

This method calls #get repeatedly until a final result is available or retries have exhausted.

Note: this method spins on #get, although honoring any retry delay. Thus, it is best to call this only if retries are limited or a retry delay has been configured.

Parameters:

  • key (Object)

    the key

  • extra_args (Array)

    extra arguments to pass to the block

  • transient_errors (Array<Class>) (defaults to: nil)

    An array of exception classes that will be treated as transient and will allow await to continue retrying. Exceptions omitted from this list will be treated as fatal errors and abort the call. Default is [StandardError].

  • max_tries (Integer, nil) (defaults to: 1)

    The maximum number of times this will call #get before giving up, or nil for a potentially unlimited number of attempts. Default is 1.

  • max_time (Numeric, nil) (defaults to: nil)

    The maximum time in seconds this will spend before giving up, or nil (the default) for a potentially unlimited timeout.

Returns:

  • (Object)

    the value

Raises:

  • (Exception)

    if a fatal error happened, or retries have been exhausted.



104
105
106
107
108
109
# File 'lib/lazy_data/dict.rb', line 104

def await(key, *extra_args, transient_errors: nil, max_tries: 1, max_time: nil)
  lookup_key(key).await(key, *extra_args,
                        transient_errors: transient_errors,
                        max_tries: max_tries,
                        max_time: max_time)
end

#expire!(key) ⇒ true, false

Force the cache for the given key to expire immediately, if computation is complete.

Any cached value will be cleared, the retry count is reset, and the next access will call the compute block as if it were the first access. Returns true if this took place. Has no effect and returns false if the computation is not yet complete (i.e. if a thread is currently computing, or if the last attempt failed and retries have not yet been exhausted.)

Parameters:

  • key (Object)

    the key

Returns:

  • (true, false)

    whether the cache was expired



135
136
137
# File 'lib/lazy_data/dict.rb', line 135

def expire!(key)
  lookup_key(key).expire!
end

#expire_all!Array<Object>

Force the values for all keys to expire immediately.

Returns:

  • (Array<Object>)

    A list of keys that were expired. A key is not included if its computation is not yet complete (i.e. if a thread is currently computing, or if the last attempt failed and retries have not yet been exhausted.)



147
148
149
150
151
152
153
154
155
# File 'lib/lazy_data/dict.rb', line 147

def expire_all!
  all_expired = []
  @mutex.synchronize do
    @key_values.each do |key, value|
      all_expired << key if value.expire!
    end
  end
  all_expired
end

#get(key, *extra_args) ⇒ Object Also known as: []

Returns the value for the given key. This will either return the value or raise an error indicating failure to compute the value. If the value was previously cached, it will return that cached value, otherwise it will either run the computation to try to determine the value, or wait for another thread that is already running the computation.

Any arguments beyond the initial key argument will be passed to the block if it is called, but are ignored if a cached value is returned.

Parameters:

  • key (Object)

    the key

  • extra_args (Array)

    extra arguments to pass to the block

Returns:

  • (Object)

    the value

Raises:

  • (Exception)

    if an error happened while computing the value



74
75
76
# File 'lib/lazy_data/dict.rb', line 74

def get(key, *extra_args)
  lookup_key(key).get(key, *extra_args)
end

#internal_state(key) ⇒ Array

Returns the current low-level state for the given key. Does not block for computation. See Value#internal_state for details.

Parameters:

  • key (Object)

    the key

Returns:

  • (Array)

    the low-level state



118
119
120
# File 'lib/lazy_data/dict.rb', line 118

def internal_state(key)
  lookup_key(key).internal_state
end

#set!(key, value, lifetime: nil) ⇒ Object

Set the cache value for the given key explicitly and immediately. If a computation is in progress, it is "detached" and its result will no longer be considered.

Parameters:

  • key (Object)

    the key

  • value (Object)

    the value to set

  • lifetime (Numeric) (defaults to: nil)

    the lifetime until expiration in seconds, or nil (the default) for no expiration.

Returns:

  • (Object)

    the value



168
169
170
# File 'lib/lazy_data/dict.rb', line 168

def set!(key, value, lifetime: nil)
  lookup_key(key).set!(value, lifetime: lifetime)
end